반응형

해당 튜토리얼에서 GBuffer Render Target을 사용하였을 때, 해결하지 못한 이슈가 있다.

Raytracing Shader, Ratracing Skylight, Mobile Deferred Rendering

위의 사항은 Raytracing에 대한 깊은 이해가 필요할 듯 하다.

때문에 Use GBuffer는 선택으로 두었으며, 필수 진행은 아니니, 넘겨도 된다.


Global Cell Shading Texture 변수를 추가해준다.

// SceneTexturesConfig.h

BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FSceneTextureUniformParameters, ENGINE_API)

	~~ ... ~~
    
	// GBuffer
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferATexture)
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferBTexture)
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferCTexture)
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferDTexture)
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferETexture)
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferFTexture)
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferVelocityTexture)
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferCellShading)

	~~ ... ~~
    
END_GLOBAL_SHADER_PARAMETER_STRUCT()
// SceneTextureParameters.h

/** Contains reference to scene GBuffer textures. */
BEGIN_SHADER_PARAMETER_STRUCT(FSceneTextureParameters, )

	~~ ... ~~
    
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferFTexture)
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferVelocityTexture)
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferCellShadingTexture)
END_SHADER_PARAMETER_STRUCT()

 

선언한 변수를 초기화해준다.

// SceneTexturesConfig.cpp

void FSceneTexturesConfig::Init(const FSceneTexturesConfigInitSettings& InitSettings)
{
	~~ ... !!
    
	if (!BindingCache.bInitialized || BindingCache.GBufferParams != DefaultParams)
    {
        for (uint32 Layout = 0; Layout < GBL_Num; ++Layout)
        {
            GBufferParams[Layout] = (Layout == GBL_Default) ? DefaultParams : FShaderCompileUtilities::FetchGBufferParamsRuntime(ShaderPlatform, (EGBufferLayout)Layout);
            const FGBufferInfo GBufferInfo = FetchFullGBufferInfo(GBufferParams[Layout]);

            BindingCache.Bindings[Layout].GBufferA = FindGBufferBindingByName(GBufferInfo, TEXT("GBufferA"));
            BindingCache.Bindings[Layout].GBufferB = FindGBufferBindingByName(GBufferInfo, TEXT("GBufferB"));
            BindingCache.Bindings[Layout].GBufferC = FindGBufferBindingByName(GBufferInfo, TEXT("GBufferC"));
            BindingCache.Bindings[Layout].GBufferD = FindGBufferBindingByName(GBufferInfo, TEXT("GBufferD"));
            BindingCache.Bindings[Layout].GBufferE = FindGBufferBindingByName(GBufferInfo, TEXT("GBufferE"));
            BindingCache.Bindings[Layout].GBufferVelocity = FindGBufferBindingByName(GBufferInfo, TEXT("Velocity"));
            BindingCache.Bindings[Layout].GBufferCellShading = FindGBufferBindingByName(GBufferInfo, TEXT("GBufferCellShading"));
        }

    	~~ ... !!

    }
        
    ~~ ... ~~
}

 

마찬가지로 GBuffer Target으로 설정할 수 있도록, Binding 대상에 포함해준다.

// SceneTexturesConfig.cpp

uint32 FSceneTexturesConfig::GetGBufferRenderTargetsInfo(FGraphicsPipelineRenderTargetsInfo& RenderTargetsInfo, EGBufferLayout Layout) const 
{
	~~ ... ~~
    
	// Setup the other render targets
	if (bIsUsingGBuffers)
	{
		~~ ... ~~

		const FGBufferBindings& Bindings = GBufferBindings[Layout];
		IncludeBindingIfValid(Bindings.GBufferA);
		IncludeBindingIfValid(Bindings.GBufferB);
		IncludeBindingIfValid(Bindings.GBufferC);
		IncludeBindingIfValid(Bindings.GBufferD);
		IncludeBindingIfValid(Bindings.GBufferE);
		IncludeBindingIfValid(Bindings.GBufferVelocity);
		IncludeBindingIfValid(Bindings.GBufferCellShadingTexture);
	}
    
	~~ ... ~~
}

 

선언한 변수의 초기화 코드를 추가해준다.

// SceneTextures.cpp

void SetupSceneTextureUniformParameters(
	FRDGBuilder& GraphBuilder,
	const FSceneTextures* SceneTextures,
	ERHIFeatureLevel::Type FeatureLevel,
	ESceneTextureSetupMode SetupMode,
	FSceneTextureUniformParameters& SceneTextureParameters)
{
	~~ ... ~~
    
	SceneTextureParameters.CustomStencilTexture = SystemTextures.StencilDummySRV;
	SceneTextureParameters.GBufferCellShadingTexture = SystemTextures.Black;

	if (SceneTextures)
	{
		~~ ... ~~

		if (IsUsingGBuffers(ShaderPlatform))
		{
			~~ ... ~~

			if (EnumHasAnyFlags(SetupMode, ESceneTextureSetupMode::GBufferF) && HasBeenProduced(SceneTextures->GBufferF))
			{
				SceneTextureParameters.GBufferFTexture = SceneTextures->GBufferF;
			}

			if (EnumHasAnyFlags(SetupMode, ESceneTextureSetupMode::GBufferCellShading) && HasBeenProduced(SceneTextures->GBufferCellShading))
			{
				SceneTextureParameters.GBufferCellShadingTexture = SceneTextures->GBufferCellShading;
			}
		}

		~~ ... ~~

	}
}

위의 ESceneTextureSetupMode 내에 GBufferCellShading Type을 추가해주어야, Enum에서 사용이 가능하다.

// SceneRenderTargetParameters.h

enum class ESceneTextureSetupMode : uint32
{
	None			= 0,
	SceneColor		= 1 << 0,
	SceneDepth		= 1 << 1,
	SceneVelocity		= 1 << 2,
	GBufferA		= 1 << 3,
	GBufferB		= 1 << 4,
	GBufferC		= 1 << 5,
	GBufferD		= 1 << 6,
	GBufferE		= 1 << 7,
	GBufferF		= 1 << 8,
	GBufferCellShading	= 1 << 9,
	SSAO			= 1 << 10,
	CustomDepth		= 1 << 11,
	GBuffers		= GBufferA | GBufferB | GBufferC | GBufferD | GBufferE | GBufferF,
	All				= SceneColor | SceneDepth | SceneVelocity | GBuffers | SSAO | CustomDepth
};
ENUM_CLASS_FLAGS(ESceneTextureSetupMode);

 

 

GBuffer의 선언과 초기화를 완료헀으니, 사용되는 부분들에 해당 변수를 추가해야한다.

// PlanarReflectionRendering.cpp (Reflection Rendering)

void FDeferredShadingSceneRenderer::RenderDeferredPlanarReflections(FRDGBuilder& GraphBuilder, const FSceneTextureParameters& SceneTextures, const FViewInfo& View, FRDGTextureRef& ReflectionsOutputTexture)
{
	~~ ... ~~
    
	PassParameters->SceneTextures.GBufferCTexture = SceneTextures.GBufferCTexture;
	PassParameters->SceneTextures.GBufferDTexture = SceneTextures.GBufferDTexture;
	PassParameters->SceneTextures.GBufferETexture = SceneTextures.GBufferETexture;
	PassParameters->SceneTextures.GBufferFTexture = SceneTextures.GBufferFTexture;
	PassParameters->SceneTextures.GBufferVelocityTexture = SceneTextures.GBufferVelocityTexture;
	PassParameters->SceneTextures.GBufferCellShadingTexture = SceneTextures.GBufferCellShadingTexture;
    
    ~~ ... ~~
}
// PostProcessBufferInspector.cpp (Pixel Inspector Pass)

~~ ... ~~

BEGIN_SHADER_PARAMETER_STRUCT(FPixelInspectorParameters, )

	~~ ... ~~
    
	RDG_TEXTURE_ACCESS(SceneDepth, ERHIAccess::CopySrc)
	RDG_TEXTURE_ACCESS(OriginalSceneColor, ERHIAccess::CopySrc)
	RDG_TEXTURE_ACCESS(GBufferCellShading, ERHIAccess::CopySrc)
END_SHADER_PARAMETER_STRUCT()

void ProcessPixelInspectorRequests(
	FRHICommandListImmediate& RHICmdList,
	const FViewInfo& View,
	const FPixelInspectorParameters& Parameters,
	const FIntRect SceneColorViewRect)
{
	~~ ... ~~
    
    if (Parameters.GBufferF)
    {
        FRHITexture* SourceBufferF = Parameters.GBufferF->GetRHI();
        if (DestinationBufferBCDEF->GetFormat() == SourceBufferF->GetFormat())
        {
            FRHICopyTextureInfo CopyInfo;
            CopyInfo.SourcePosition = SourcePoint;
            CopyInfo.Size = FIntVector(1, 1, 1);
            RHICmdList.CopyTexture(SourceBufferF, DestinationBufferBCDEF, CopyInfo);
        }
    }

    if (Parameters.GBufferCellShading)
    {
        FRHITexture* SourceBufferCellShading = Parameters.GBufferCellShading->GetRHI();
        if (DestinationBufferBCDEF->GetFormat() == SourceBufferCellShading->GetFormat())
        {
            FRHICopyTextureInfo CopyInfo;
            CopyInfo.SourcePosition = SourcePoint;
            CopyInfo.DestPosition = FIntVector(4, 0, 0);
            CopyInfo.Size = FIntVector(1, 1, 1);
            RHICmdList.CopyTexture(SourceBufferCellShading, DestinationBufferBCDEF, CopyInfo);
        }
    }
    
    ~~ ... ~~
}

FScreenPassTexture AddPixelInspectorPass(FRDGBuilder& GraphBuilder, const FViewInfo& View, const FPixelInspectorInputs& Inputs)
{
	~~ ... ~~

	// Perform copies of scene textures data into staging resources for visualization.
	{
		~~ ... ~~

		FPixelInspectorParameters* PassParameters = GraphBuilder.AllocParameters<FPixelInspectorParameters>();
		PassParameters->GBufferA = SceneTextures.GBufferATexture;
		PassParameters->GBufferB = SceneTextures.GBufferBTexture;
		PassParameters->GBufferC = SceneTextures.GBufferCTexture;
		PassParameters->GBufferD = SceneTextures.GBufferDTexture;
		PassParameters->GBufferE = SceneTextures.GBufferETexture;
		PassParameters->GBufferF = SceneTextures.GBufferFTexture;
		PassParameters->SceneColor = Inputs.SceneColor.Texture;
		PassParameters->SceneColorBeforeTonemap = Inputs.SceneColorBeforeTonemap.Texture;
		PassParameters->SceneDepth = SceneTextures.SceneDepthTexture;
		PassParameters->OriginalSceneColor = Inputs.OriginalSceneColor.Texture;
		PassParameters->GBufferCellShading = SceneTextures.GBufferCellShadingTexture;

		~~ ... ~~
	}
    
	~~ ... ~~
}
// SceneTextureParameters.cpp (Getter Scene Texture Parameter)

FSceneTextureParameters GetSceneTextureParameters(FRDGBuilder& GraphBuilder, const FSceneTextures& SceneTextures)
{
	~~ ... ~~
    
	// Registers all the scene texture from the scene context. No fallback is provided to catch mistake at shader parameter validation time
	// when a pass is trying to access a resource before any other pass actually created it.
	Parameters.GBufferVelocityTexture = GetIfProduced(SceneTextures.Velocity);
	Parameters.GBufferATexture = GetIfProduced(SceneTextures.GBufferA);
	Parameters.GBufferBTexture = GetIfProduced(SceneTextures.GBufferB);
	Parameters.GBufferCTexture = GetIfProduced(SceneTextures.GBufferC);
	Parameters.GBufferDTexture = GetIfProduced(SceneTextures.GBufferD);
	Parameters.GBufferETexture = GetIfProduced(SceneTextures.GBufferE);
	Parameters.GBufferFTexture = GetIfProduced(SceneTextures.GBufferF, SystemTextures.MidGrey);
	Parameters.GBufferCellShadingTexture = GetIfProduced(SceneTextures.GBufferCellShading);

	return Parameters;
}

FSceneTextureParameters GetSceneTextureParameters(FRDGBuilder& GraphBuilder, TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTextureUniformBuffer)
{
	~~ ... ~~
    
	Parameters.GBufferATexture = (*SceneTextureUniformBuffer)->GBufferATexture;
	Parameters.GBufferBTexture = (*SceneTextureUniformBuffer)->GBufferBTexture;
	Parameters.GBufferCTexture = (*SceneTextureUniformBuffer)->GBufferCTexture;
	Parameters.GBufferDTexture = (*SceneTextureUniformBuffer)->GBufferDTexture;
	Parameters.GBufferETexture = (*SceneTextureUniformBuffer)->GBufferETexture;
	Parameters.GBufferFTexture = (*SceneTextureUniformBuffer)->GBufferFTexture;
	Parameters.GBufferVelocityTexture = (*SceneTextureUniformBuffer)->GBufferVelocityTexture;
	Parameters.GBufferCellShadingTexture = (*SceneTextureUniformBuffer)->GBufferCellShadingTexture;
	return Parameters;
}

~~ ... ~~

Cell Shading에 사용할 GBuffer Texture를 추가 및 사용 준비가 완료되었다.

이제 GBuffer Texture에 실제 들어갈 값에 대한 초기화가 필요하다.


위에서 정의한 Texture에 넣어줄 변수를 Scene Textures Class에서 선언해준다.

// SceneTextures.h

struct FSceneTextures : public FMinimalSceneTextures
{
	~~ ... ~~
    
	// (Deferred) Textures containing geometry information for deferred shading.
	FRDGTextureRef GBufferA{};
	FRDGTextureRef GBufferB{};
	FRDGTextureRef GBufferC{};
	FRDGTextureRef GBufferD{};
	FRDGTextureRef GBufferE{};
	FRDGTextureRef GBufferF{};
	FRDGTextureRef GBufferCellShading{};
}

Fast VRam으로 사용하기 위한 Flag 정의도 추가해준다.

// SceneRendering.h

struct FFastVramConfig
{
	~~ ... ~~
    
	ETextureCreateFlags GBufferA;
	ETextureCreateFlags GBufferB;
	ETextureCreateFlags GBufferC;
	ETextureCreateFlags GBufferD;
	ETextureCreateFlags GBufferE;
	ETextureCreateFlags GBufferF;
	ETextureCreateFlags GBufferVelocity;
	ETextureCreateFlags GBufferCellShading;
	ETextureCreateFlags HZB;
}

 

생성한 Flag의 Fast Vram 여부를 설정해준다.

// SceneRendering.cpp

~~ ... ~~

FASTVRAM_CVAR(GBufferA, 0);
FASTVRAM_CVAR(GBufferB, 1);
FASTVRAM_CVAR(GBufferC, 0);
FASTVRAM_CVAR(GBufferD, 0);
FASTVRAM_CVAR(GBufferE, 0);
FASTVRAM_CVAR(GBufferF, 0);
FASTVRAM_CVAR(GBufferVelocity, 0);
FASTVRAM_CVAR(GBufferCellShading, 0);
FASTVRAM_CVAR(HZB, 1);

~~ ... ~~

 

Share Texture에도 추가한다.

// TextureShareStrings.h

namespace UE::TextureShareStrings::SceneTextures
{
	// Read-only scene resources
	static constexpr auto SceneColor = TEXT("SceneColor");
	static constexpr auto SceneDepth = TEXT("SceneDepth");
	static constexpr auto SmallDepthZ = TEXT("SmallDepthZ");
	static constexpr auto GBufferA = TEXT("GBufferA");
	static constexpr auto GBufferB = TEXT("GBufferB");
	static constexpr auto GBufferC = TEXT("GBufferC");
	static constexpr auto GBufferD = TEXT("GBufferD");
	static constexpr auto GBufferE = TEXT("GBufferE");
	static constexpr auto GBufferF = TEXT("GBufferF");
	static constexpr auto GBufferCellShading = TEXT("GBufferCellShading");

	// Read-write RTTs
	static constexpr auto FinalColor = TEXT("FinalColor");
	static constexpr auto Backbuffer = TEXT("Backbuffer");
};
// TextureShareSceneViewExtension.cpp

void FTextureShareSceneViewExtension::ShareSceneViewColors_RenderThread(FRDGBuilder& GraphBuilder, const FSceneTextures& SceneTextures, const FTextureShareSceneView& InView)
{
	~~ ... ~~
    
	AddShareTexturePass(UE::TextureShareStrings::SceneTextures::GBufferA, SceneTextures.GBufferA);
	AddShareTexturePass(UE::TextureShareStrings::SceneTextures::GBufferB, SceneTextures.GBufferB);
	AddShareTexturePass(UE::TextureShareStrings::SceneTextures::GBufferC, SceneTextures.GBufferC);
	AddShareTexturePass(UE::TextureShareStrings::SceneTextures::GBufferD, SceneTextures.GBufferD);
	AddShareTexturePass(UE::TextureShareStrings::SceneTextures::GBufferE, SceneTextures.GBufferE);
	AddShareTexturePass(UE::TextureShareStrings::SceneTextures::GBufferF, SceneTextures.GBufferF);
	AddShareTexturePass(UE::TextureShareStrings::SceneTextures::GBufferCellShading, SceneTextures.GBufferCellShading);
}

Cell Shading에 사용될 GBuffer Texture의 초기화 과정에 대한 내용을 추가해주었다.


초기화된 GBuffer를 생성하여 전달하는 로직을 추가해야한다.

// GBufferInfo.h

struct FGBufferBindings
{
	FGBufferBinding GBufferA;
	FGBufferBinding GBufferB;
	FGBufferBinding GBufferC;
	FGBufferBinding GBufferD;
	FGBufferBinding GBufferE;
	FGBufferBinding GBufferVelocity;
	FGBufferBinding GBufferCellShading;
};

 

Scene Texture Binding과 RDG Texture 생성을 해준다.

// SceneTextures.cpp

uint32 FSceneTextures::GetGBufferRenderTargets(
	TArrayView<FTextureRenderTargetBinding> RenderTargets,
	EGBufferLayout Layout) const
{
	~~ ... ~~
    
    const FGBufferBindings& Bindings = Config.GBufferBindings[Layout];
    const FGBufferEntry GBufferEntries[] =
    {
        { TEXT("GBufferA"), GBufferA, Bindings.GBufferA.Index },
        { TEXT("GBufferB"), GBufferB, Bindings.GBufferB.Index },
        { TEXT("GBufferC"), GBufferC, Bindings.GBufferC.Index },
        { TEXT("GBufferD"), GBufferD, Bindings.GBufferD.Index },
        { TEXT("GBufferE"), GBufferE, Bindings.GBufferE.Index },
        { TEXT("Velocity"), Velocity, Bindings.GBufferVelocity.Index }, 
        { TEXT("GBufferCellShading"), GBufferCellShading, Bindings.GBufferCellShading.Index }
    };
    
    ~~ ... ~~
}

~~ ... ~~

void FSceneTextures::InitializeViewFamily(FRDGBuilder& GraphBuilder, FViewFamilyInfo& ViewFamily)
{
	~~ ... ~~

    if (Bindings.GBufferE.Index >= 0)
    {
        const FRDGTextureDesc Desc(FRDGTextureDesc::Create2D(Config.Extent, Bindings.GBufferE.Format, FClearValueBinding::Transparent, Bindings.GBufferE.Flags | FlagsToAdd | GFastVRamConfig.GBufferE));
        SceneTextures.GBufferE = GraphBuilder.CreateTexture(Desc, TEXT("GBufferE"));
    }

    if (Bindings.GBufferCellShading.Index >= 0)
    {
        const FRDGTextureDesc Desc(FRDGTextureDesc::Create2D(Config.Extent, Bindings.GBufferCellShading.Format, FClearValueBinding::Transparent, Bindings.GBufferCellShading.Flags | FlagsToAdd | GFastVRamConfig.GBufferCellShading));
        SceneTextures.GBufferCellShading = GraphBuilder.CreateTexture(Desc, TEXT("GBufferCellShading"));
    }
    
    ~~ ... ~~
}

 

GBuffer Slot Index를 추가해준다.

// GBufferInfo.h

enum EGBufferSlot
{
	~~ ... ~~
    
	GBS_SeparatedMainDirLight, // RGB 11.11.10
	GBS_CellShading, 
	GBS_Num
};

Enum으로 추가하므로, Enum To String에도 함께 추가해준다.

// ShaderGenerationUtil.cpp

static FString GetSlotTextName(EGBufferSlot Slot)
{
	~~ ... ~~
    
	case GBS_SeparatedMainDirLight:
		return TEXT("SeparatedMainDirLight");
	case GBS_CellShading:
		return TEXT("CellShading");
	default:
		break;
	};

	return TEXT("ERROR");
}

 

GBuffer Cell Shading Index를 -1로 초기화 선언을 하고, Index 설정이 필요하다.

Index를 설정할 때, Cell Shading 변수의 추가로 인하여, 다른 Index들의 값이 1씩 밀림을 잊지말고 확인하여야 한다.

// GBufferInfo.cpp

FGBufferInfo RENDERCORE_API FetchLegacyGBufferInfo(const FGBufferParams& Params)
{
	~~ ... ~~
    
	int32 TargetGBufferF = -1;
	int32 TargetVelocity = -1;
	int32 TargetGBufferCellShading = -1;
	int32 TargetSeparatedMainDirLight = -1;
    
    ~~ ... ~~
    
    // This code should match TBasePassPS
	if (Params.bHasVelocity == 0 && Params.bHasTangent == 0)
	{
		TargetGBufferD = 4;
		TargetGBufferCellShading = 5;
		Info.Targets[4].Init(GBT_Unorm_8_8_8_8,  TEXT("GBufferD"), false,  true,  true,  true);
		Info.Targets[5].Init(GBT_Unorm_8_8_8_8,  TEXT("GBufferCellShading"), false,  true,  true,  true);
		TargetSeparatedMainDirLight = 6;

		if (Params.bHasPrecShadowFactor)
		{
			TargetGBufferE = 6;
			Info.Targets[6].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferE"), false, true, true, true);
			TargetSeparatedMainDirLight = 7;
		}
	}
	else if (Params.bHasVelocity)
	{
		TargetVelocity = 4;
		TargetGBufferD = 5;
		TargetGBufferCellShading = 6;

		// note the false for use extra flags for velocity, not quite sure of all the ramifications, but this keeps it consistent with previous usage
		Info.Targets[4].Init(Params.bUsesVelocityDepth ? GBT_Unorm_16_16_16_16 : (IsAndroidOpenGLESPlatform(Params.ShaderPlatform) ? GBT_Float_16_16 : GBT_Unorm_16_16), TEXT("Velocity"), false, true, true, false);
		Info.Targets[5].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferD"), false, true, true, true);
		Info.Targets[6].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferCellShading"), false, true, true, true);
		TargetSeparatedMainDirLight = 7;

		if (Params.bHasPrecShadowFactor)
		{
			TargetGBufferE = 7;
			Info.Targets[7].Init(GBT_Unorm_8_8_8_8, TEXT("GBufferE"), false, true, true, false);
			TargetSeparatedMainDirLight = 8;
		}
	}
    
    ~~ ... ~~
}

같은 함수 내에 Slot에 대한 설정을 해준다.

// GBufferInfo.cpp

FGBufferInfo RENDERCORE_API FetchLegacyGBufferInfo(const FGBufferParams& Params)
{
	~~ ... ~~
    
	// GBufferD
	Info.Slots[GBS_CustomData] = FGBufferItem(GBS_CustomData, GBC_Raw_Unorm_8_8_8_8, GBCH_Both);
	Info.Slots[GBS_CustomData].Packing[0] = FGBufferPacking(TargetGBufferD, 0, 0);
	Info.Slots[GBS_CustomData].Packing[1] = FGBufferPacking(TargetGBufferD, 1, 1);
	Info.Slots[GBS_CustomData].Packing[2] = FGBufferPacking(TargetGBufferD, 2, 2);
	Info.Slots[GBS_CustomData].Packing[3] = FGBufferPacking(TargetGBufferD, 3, 3);

	// GBufferCellShading
	Info.Slots[GBS_CellShading] = FGBufferItem(GBS_CellShading, GBC_Raw_Unorm_8, GBCH_Both);
	Info.Slots[GBS_CellShading].Packing[0] = FGBufferPacking(TargetGBufferCellShading, 0, 3);
    
    ~~ ... ~~
}

 

Cell Shading GBuffer 관련 내용을 HLSL 내용에 수정을 해야한다.

 

Deferred Shading 내에 Cell Shading Texture Sampler를 추가 정의하고, GBuffer Data에 Cell Shading 값을 추가한다.

// DeferredShadingCommon.ush

~~ ... ~~

// Matches FSceneTextureParameters
Texture2D SceneDepthTexture;
Texture2D<uint2> SceneStencilTexture;
Texture2D GBufferATexture;
Texture2D GBufferBTexture;
Texture2D GBufferCTexture;
Texture2D GBufferDTexture;
Texture2D GBufferETexture;
Texture2D GBufferVelocityTexture;
Texture2D GBufferFTexture;
Texture2D GBufferCellShadingTexture;
Texture2D<uint> SceneLightingChannels;

#define SceneDepthTextureSampler GlobalPointClampedSampler
#define GBufferATextureSampler GlobalPointClampedSampler
#define GBufferBTextureSampler GlobalPointClampedSampler
#define GBufferCTextureSampler GlobalPointClampedSampler
#define GBufferDTextureSampler GlobalPointClampedSampler
#define GBufferETextureSampler GlobalPointClampedSampler
#define GBufferFTextureSampler GlobalPointClampedSampler
#define GBufferVelocityTextureSampler GlobalPointClampedSampler
#define GBufferCellShadingTextureSampler GlobalPointClampedSampler

~~ ... ~~

// all values that are output by the forward rendering pass
struct FGBufferData
{
	~~ ... ~~

	// Curvature for mobile subsurface profile
	half Curvature;

	float4 CellShading;
};

~~ ... ~~
// SceneTexturesCommon.ush

~~ ... ~~

#define SceneTexturesStruct_SceneColorTextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_SceneDepthTextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_ScenePartialDepthTextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_CustomDepthTextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_GBufferATextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_GBufferBTextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_GBufferCTextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_GBufferDTextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_GBufferETextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_GBufferFTextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_GBufferVelocityTextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_ScreenSpaceAOTextureSampler SceneTexturesStruct.PointClampSampler
#define SceneTexturesStruct_GBufferCellShadingTextureSampler SceneTexturesStruct.PointClampSampler

~~ ... ~~

 

Deferred Decal의 경우에 Dummy값을 추가해야 한다. (해당 로직의 필요성은 아직 이해하지 못하여 확인이 필요하다..)

// DeferredDecal.usf

~~ ... ~~

// is called in MainPS() from PixelShaderOutputCommon.usf
void FPixelShaderInOut_MainPS(inout FPixelShaderIn In, inout FPixelShaderOut Out)
{
	~~ ... ~~

	FGBufferData GBufferData;
	GBufferData.WorldNormal = MaterialParameters.WorldNormal;
	GBufferData.BaseColor = GetMaterialBaseColor(PixelMaterialInputs);
	GBufferData.Metallic = GetMaterialMetallic(PixelMaterialInputs);
	GBufferData.Specular = GetMaterialSpecular(PixelMaterialInputs);
	GBufferData.Roughness = GetMaterialRoughness(PixelMaterialInputs);
	GBufferData.CustomData = 0;
	GBufferData.IndirectIrradiance = 0;
	GBufferData.PrecomputedShadowFactors = 1;
	GBufferData.GBufferAO = GetMaterialAmbientOcclusion(PixelMaterialInputs);
	GBufferData.ShadingModelID = SHADINGMODELID_DEFAULT_LIT;
	GBufferData.SelectiveOutputMask = 0;
	GBufferData.PerObjectGBufferData = 1; 
	GBufferData.DiffuseIndirectSampleOcclusion = 0;
	GBufferData.Velocity = 0;
	GBufferData.CellShading = 0;
    
    ~~ ... ~~
}

~~ ... ~~

Raytracing 사용하기 위한 수정이다.

// RayTracingDeferredShadingCommon.ush

FGBufferData GetGBufferDataFromSceneTexturesLoad(uint2 PixelCoord, bool bGetNormalizedNormal = true)
{
	float4 GBufferA = GBufferATexture.Load(int3(PixelCoord, 0));
	float4 GBufferB = GBufferBTexture.Load(int3(PixelCoord, 0));
	float4 GBufferC = GBufferCTexture.Load(int3(PixelCoord, 0));
	float4 GBufferD = GBufferDTexture.Load(int3(PixelCoord, 0));
	float4 GBufferE = GBufferETexture.Load(int3(PixelCoord, 0));
	float4 GBufferF = GBufferFTexture.Load(int3(PixelCoord, 0));
	float4 GBufferCellShading = GBufferCellShadingTexture.Load(int3(PixelCoord, 0));

	~~ ... ~~

	float SceneDepth = ConvertFromDeviceZ(DeviceZ);

	return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromPixelPos(PixelCoord), GBufferCellShading);
}

FGBufferData GetGBufferDataFromPayload(in FMaterialClosestHitPayload Payload)
{
	FGBufferData GBufferData = (FGBufferData)0;
#if !STRATA_ENABLED

	~~ ... ~~
    
	GBufferData.WorldTangent = Payload.WorldTangent;
	GBufferData.Anisotropy = Payload.Anisotropy;
	GBufferData.CellShading = float4(Payload.CellShading, 0, 0, 0);
#endif
	return GBufferData;
}

DecodeGBufferData에 GBufferCellShading Parameter가 추가되었으므로, 함수도 수정해주어야 한다.

// DeferredShadingCommon.ush

~~ ... ~~

FGBufferData DecodeGBufferData(

	~~ ... ~~
    
	bool bChecker, 
	float InGBufferCellShading)
{
	~~ ... ~~

	GBuffer.CustomData = HasCustomGBufferData(GBuffer.ShadingModelID) ? InGBufferD : 0;
	GBuffer.CellShading = HasCustomGBufferData(GBuffer.ShadingModelID) ? InGBufferCellShading : 0;

	~~ ... ~~

}

~~ ... ~~

 

Payload 구조체에 Cell Shading 정보를 포함한다.

// RayTracingCommon.ush

~~ ... ~~

struct FMaterialClosestHitPayload : FMinimalPayload
{
	~~ ... ~~
    
	// Quite some code assume FRayHitInfo has a WorldPos
	// So keep it here and force to re-construct it in Unpack call using ray information.
	// It is not packed in FRayHitInfoPacked
	float3 TranslatedWorldPos;			// 136       0       (derived)
	uint Flags;							// 148       0       6bits (packed with ShadingModelID)
	float3 WorldTangent;				// 152       6       48bits
	float Anisotropy;					// 164       2       16bits (packed with WorldTangent)
	float CellShading;					// 166       2       16bits (packed with WorldTangent)
										// 168 total

	~~ ... ~~

};

struct FPackedMaterialClosestHitPayload : FMinimalPayload
{
	~~ ... ~~
    
	uint WorldTangentAndAnisotropy[2];                   // 8  bytes
	uint PackedGeometryNormal;                           // 4  bytes
	half CellShading;									 // 2  bytes
	                                                     // 66 bytes total

	~~ ... ~~


	float GetCellShading() { return CellShading; }
	void SetCellShading(float NewCellShading) { CellShading = NewCellShading; }
};

~~ ... ~~

 

Packed & Unpack 함수에 데이터를 설정해준다.

// RadyTracingCommon.ush

~~ ... ~~

FPackedMaterialClosestHitPayload PackRayTracingPayload(FMaterialClosestHitPayload Input, in FRayCone RayCone)
{
	~~ ... ~~
    
	Output.WorldTangentAndAnisotropy[0] |= f32tof16(Input.WorldTangent.y) << 16;
	Output.WorldTangentAndAnisotropy[1]  = f32tof16(Input.WorldTangent.z);
	Output.WorldTangentAndAnisotropy[1] |= f32tof16(Input.Anisotropy) << 16;

	Output.SetCellShading(Input.CellShading);

	return Output;
}

FMaterialClosestHitPayload UnpackRayTracingPayload(FPackedMaterialClosestHitPayload Input, FRayDesc Ray)
{
	~~ ... ~~
    
	Output.Anisotropy         = Input.GetAnisotropy();
	Output.CellShading        = Input.GetCellShading();

	Output.DiffuseColor  = Output.BaseColor - Output.BaseColor * Output.Metallic;
	Output.SpecularColor = ComputeF0(Output.Specular, Output.BaseColor, Output.Metallic);
	Output.TranslatedWorldPos = Ray.Origin + Output.HitT * Ray.Direction;

	return Output;
}

~~ ... ~~

이제 Cell Shading로 메모리를 할당하여 사용할 수 있다.


예제와는 다르게 Shader Compile Error가 발생한다.

이는 Ray Tracing 로직 중, DecodeGBufferData 함수에 Cell Shading 변수 파라미터를 추가하면서, 기존 DecodeGBufferData 함수를 사용하던 함수들의 Parameter가 부족해서 생기는 오류이다.

 

Shader Error를 자세히 보기 위해서는 ConsoleVariables.ini 파일에 r.ShaderDevelopmentMode=1 를 추가하면 확인이 가능하다.

// ConsoleVariables.ini

~~ ... ~~

r.ShaderDevelopmentMode=1

// DeferredShadingCommon.ush

~~ ... ~~

FGBufferData GetGBufferDataUint(uint2 PixelPos, bool bGetNormalizedNormal = true)
	{
		~~ ... ~~
        
		return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromPixelPos(PixelPos), 0);
	#endif
	}
    
~~ ... ~~
// DeferredShadingCommon.ush

~~ ... ~~

FGBufferData GetGBufferDataFromSceneTextures(float2 UV, bool bGetNormalizedNormal = true)
{
#if GBUFFER_REFACTOR
	return DecodeGBufferDataSceneTextures(UV,bGetNormalizedNormal);
#else
	float4 GBufferA = GBufferATexture.SampleLevel(GBufferATextureSampler, UV, 0);
	float4 GBufferB = GBufferBTexture.SampleLevel(GBufferBTextureSampler, UV, 0);
	float4 GBufferC = GBufferCTexture.SampleLevel(GBufferCTextureSampler, UV, 0);
	float4 GBufferD = GBufferDTexture.SampleLevel(GBufferDTextureSampler, UV, 0);
	float4 GBufferE = GBufferETexture.SampleLevel(GBufferETextureSampler, UV, 0);
	float4 GBufferF = GBufferFTexture.SampleLevel(GBufferFTextureSampler, UV, 0);
	float4 GBufferVelocity = GBufferVelocityTexture.SampleLevel(GBufferVelocityTextureSampler, UV, 0);
	float4 GBufferCellShading = GBufferFTexture.SampleLevel(GBufferCellShadingTextureSampler, UV, 0);

	uint CustomStencil = 0;
	float CustomNativeDepth = 0;

	float DeviceZ = SampleDeviceZFromSceneTextures(UV);

	float SceneDepth = ConvertFromDeviceZ(DeviceZ);

	return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromSceneColorUV(UV), GBufferCellShading);
#endif
}

~~ ... ~~
// DeferredShadingCommon.ush

~~ ... ~~

FGBufferData GetGBufferData(float2 UV, bool bGetNormalizedNormal = true)
{
	~~ ... ~~
    
	return DecodeGBufferData(GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferVelocity, CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromSceneColorUV(UV), 0);
#endif
}

~~ ... ~~
// SSDCommon.ush

~~ ... ~~

FSSDCompressedSceneInfos SampleCompressedSceneMetadata(
	const bool bPrevFrame,
	float2 BufferUV, uint2 PixelCoord)
#if CONFIG_METADATA_BUFFER_LAYOUT == METADATA_BUFFER_LAYOUT_DISABLED
{
  	~~ ... ~~
    
	FGBufferData GBufferData;
	if (bPrevFrame)
	{
		~~ ... ~~
        
		float4 GBufferF = 0.5f;
		float4 GBufferVelocity = 0.0;
		float4 GBufferCellShading = 0.0;

		bool bGetNormalizedNormal = false;

		GBufferData = DecodeGBufferData(
			GBufferA, GBufferB, GBufferC, GBufferD, GBufferE, GBufferF, GBufferVelocity,
			CustomNativeDepth, CustomStencil, SceneDepth, bGetNormalizedNormal, CheckerFromSceneColorUV(BufferUV), GBufferCellShading);
	}
	else
	{
		GBufferData = GetGBufferDataFromSceneTextures(BufferUV);	
	}
	return MaterialToCompressedSceneMetadata(GBufferData.Depth, GBufferData.WorldNormal, GBufferData.Roughness, GBufferData.ShadingModelID);
  #endif  // STRATA_ENABLED
}

~~ ... ~~
반응형

+ Recent posts