티스토리 뷰

Chap 7. G-Buffer

C.  C++ 측에서의 GBuffer 변경

https://dev.epicgames.com/community/learning/tutorials/2R5x/unreal-engine-new-shading-models-and-changing-the-gbuffer

 

New shading models and changing the GBuffer | Community tutorial

Implementing a Celshading model directly into UE5.1 source. This celshading use a linear color curve atlas to drive all the values. Learn how to set you...

dev.epicgames.com


이 전까지는 GBuffer가 어떤방식으로 생성되는지를 알아보았다. 지금은 직접 새로운 GBuffer를 추가하는 작업을 진행한다.

 

C. GBuffer 변경(C++ 측)

GBuffer 텍스처 생성

Gbuffer의 장면 텍스처를 생성하기 위해 Unreal은 SceneTexturesConfig.h 의 셰이더 구조체  FSceneTextureUniformParameters를  사용합니다 . 이것이 첫 번째 변경 사항입니다.

SceneTexturesConfig.hSHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferVelocityTexture) 아래에

SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferCelshadingTexture) // Celshading Lucas: Add a new celshading scene texture

를 추가.

그런 다음 SceneTexturesConfig.cpp 파일 내 FSceneTexturesConfig::Init() 함수에서 셀쉐이딩 GBuffer를 초기화합니다. 또한 바로 아래 FSceneTexturesConfig::GetGBufferRenderTargetsInfo() 함수에 있습니다 .

 

SceneTexturesConfig.cpp 파일 내부에 레이아웃 바인딩을 추가.

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"));
		// Celshading Lucas: Bind GBufferCelshading to scene texture
		// **FSceneTexturesConfig::Init()** 함수 내부에 레이아웃 바인딩 추가!
		BindingCache.Bindings[Layout].GBufferCelshading = FindGBufferBindingByName(GBufferInfo, TEXT("GBufferCelshading")); 
	}

	BindingCache.GBufferParams = DefaultParams;
	BindingCache.bInitialized = true;
}

 

또한 FSceneTexturesConfig::GetGBufferRenderTargetsInfo() 함수 내부에도 G버퍼에 대한 내용을 추가해준다.

const FGBufferBindings& Bindings = GBufferBindings[Layout];
		IncludeBindingIfValid(Bindings.GBufferA);
		IncludeBindingIfValid(Bindings.GBufferB);
		IncludeBindingIfValid(Bindings.GBufferC);
		IncludeBindingIfValid(Bindings.GBufferD);
		IncludeBindingIfValid(Bindings.GBufferE);
		IncludeBindingIfValid(Bindings.GBufferVelocity);
		// Celshading Lucas: include GBufferCelshading binding to the render targets info result
		// GBufferCelshading 추가!
		IncludeBindingIfValid(Bindings.GBufferCelshading);

재빌드 성공!

 

오류가 발생하지만 이는 정상적인 현상이므로 걱정하지 마세요. 아직 GBufferCelshading  을 구현하지 않았습니다 .

이제 엔진 시작 시 텍스처를 초기화해야 합니다. 왜냐하면 View 구조체와 마찬가지로 렌더링 스레드도 nullptr을 좋아하지 않기 때문입니다.

SetupSceneTextureUniformParameters() 함수의 SceneTextures.cpp 로 이동하여 GBufferCelshadingTexture를 추가합니다 .

SceneTextures.cpp 내부의 SetupSceneTextureUniformParameters() 함수 내에 SceneTextureParameters.GBufferCelshadingTexture = SystemTextures.Black;를 추가.

void SetupSceneTextureUniformParameters(
	FRDGBuilder& GraphBuilder,
	const FSceneTextures* SceneTextures,
	ERHIFeatureLevel::Type FeatureLevel,
	ESceneTextureSetupMode SetupMode,
	FSceneTextureUniformParameters& SceneTextureParameters)
{
	const FRDGSystemTextures& SystemTextures = FRDGSystemTextures::Get(GraphBuilder);
	SceneTextureParameters.PointClampSampler = TStaticSamplerState<SF_Point>::GetRHI();
	SceneTextureParameters.SceneColorTexture = SystemTextures.Black;
	SceneTextureParameters.SceneDepthTexture = SystemTextures.DepthDummy;
	SceneTextureParameters.GBufferATexture = SystemTextures.Black;
	SceneTextureParameters.GBufferBTexture = SystemTextures.Black;
	SceneTextureParameters.GBufferCTexture = SystemTextures.Black;
	SceneTextureParameters.GBufferDTexture = SystemTextures.Black;
	SceneTextureParameters.GBufferETexture = SystemTextures.Black;
	SceneTextureParameters.GBufferFTexture = SystemTextures.MidGrey;
	SceneTextureParameters.GBufferVelocityTexture = SystemTextures.Black;
	SceneTextureParameters.ScreenSpaceAOTexture = GetScreenSpaceAOFallback(SystemTextures);
	SceneTextureParameters.CustomDepthTexture = SystemTextures.DepthDummy;
	SceneTextureParameters.CustomStencilTexture = SystemTextures.StencilDummySRV;
    // 추가 위치
	SceneTextureParameters.GBufferCelshadingTexture = SystemTextures.Black;

// [...]

if (EnumHasAnyFlags(SetupMode, ESceneTextureSetupMode::GBufferE) && HasBeenProduced(SceneTextures->GBufferE))
	{
		SceneTextureParameters.GBufferETexture = SceneTextures->GBufferE;
	}
	if (EnumHasAnyFlags(SetupMode, ESceneTextureSetupMode::GBufferF) && HasBeenProduced(SceneTextures->GBufferF))
	{
		SceneTextureParameters.GBufferFTexture = SceneTextures->GBufferF;
	}
	// Celshading Lucas : if produced, bind the celshading RDG texture to the shader texture
	// Celshading G버퍼 추가
	if (EnumHasAnyFlags(SetupMode, ESceneTextureSetupMode::GBufferCelshading) && HasBeenProduced(SceneTextures->GBufferCelshading))
	{
		SceneTextureParameters.GBufferCelshadingTexture = SceneTextures->GBufferCelshading;
	}
// [...]
}

 

이제 UE에는 나중에 basepass에서 다른 매개변수로 매개변수를 전달하는 또 다른 구조체가 있는 것 같습니다. SceneTextureParameters.h 파일의 FSceneTextureParameters 입니다 .

/** Contains reference to scene GBuffer textures. */
BEGIN_SHADER_PARAMETER_STRUCT(FSceneTextureParameters, )
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SceneDepthTexture)
	SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D<uint2>, SceneStencilTexture)
	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)
	// Celshading Lucas: Add GBufferCelshadingTexture to render target parameters
	// GBufferCelshading 추가
	SHADER_PARAMETER_RDG_TEXTURE(Texture2D, GBufferCelshadingTexture) 
	END_SHADER_PARAMETER_STRUCT()

 

이제 사용되는 모든 함수에서 이 새 매개변수를 참조해야 합니다. 먼저 PlanarReflectionRendering.cpp 파일의 FDeferredShadingSceneRenderer::RenderDeferredPlanarReflections() 함수에 있습니다  . 이는 평면 반사 렌더링의 진입점입니다.

void FDeferredShadingSceneRenderer::RenderDeferredPlanarReflections(FRDGBuilder& GraphBuilder, const FSceneTextureParameters& SceneTextures, const FViewInfo& View, FRDGTextureRef& ReflectionsOutputTexture)
{
	check(HasDeferredPlanarReflections(View));

	// Allocate planar reflection texture
	bool bClearReflectionsOutputTexture = false;
	if (!ReflectionsOutputTexture)
	{
		FRDGTextureDesc Desc = FRDGTextureDesc::Create2D(
			SceneTextures.SceneDepthTexture->Desc.Extent,
			PF_FloatRGBA, FClearValueBinding(FLinearColor(0, 0, 0, 0)),
			TexCreate_ShaderResource | TexCreate_RenderTargetable);

		ReflectionsOutputTexture = GraphBuilder.CreateTexture(Desc, TEXT("PlanarReflections"));
		bClearReflectionsOutputTexture = true;
	}

	FPlanarReflectionPS::FParameters* PassParameters = GraphBuilder.AllocParameters<FPlanarReflectionPS::FParameters>();
	PassParameters->SceneTextures.SceneDepthTexture = SceneTextures.SceneDepthTexture;
	PassParameters->SceneTextures.GBufferATexture = SceneTextures.GBufferATexture;
	PassParameters->SceneTextures.GBufferBTexture = SceneTextures.GBufferBTexture;

	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;
	// Celshading Lucas: pass scene texture parameters to planar reflection renderer
	// 장면 텍스처 매개변수를 평면 반사 렌더러에 전달합니다.
	PassParameters->SceneTextures.GBufferCelshadingTexture = SceneTextures.GBufferCelshadingTexture;
	// [...]
}

 

그런 다음 PostProcessBufferInspector.cpp 파일에  AddPixelInspectorPass() 함수가 있습니다 .

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;
		// Celshading Lucas: pass scene texture parameter to pixel inspector
		// 장면 텍스처 매개변수를 픽셀 검사기에 전달합니다.
		PassParameters->GBufferCelshading = SceneTextures.GBufferCelshadingTexture;

 

마지막으로  SceneTextureParameters.cpp 에서 두 getter FSceneTextureParameters::GetSceneTextureParameters() 는 다음과 같습니다.

FSceneTextureParameters GetSceneTextureParameters(FRDGBuilder& GraphBuilder, const FSceneTextures& SceneTextures)
{
	const auto& SystemTextures = FRDGSystemTextures::Get(GraphBuilder);

	FSceneTextureParameters Parameters;

	// Should always have a depth buffer around allocated, since early z-pass is first.
	Parameters.SceneDepthTexture = SceneTextures.Depth.Resolve;
	Parameters.SceneStencilTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateWithPixelFormat(Parameters.SceneDepthTexture, PF_X24_G8));

	// 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);
	// Celshading Lucas: Get Celshading scene texture
	// 셀쉐이딩 장면 텍스처 가져오기
	Parameters.GBufferCelshadingTexture = GetIfProduced(SceneTextures.GBufferCelshading);

	return Parameters;
}
FSceneTextureParameters GetSceneTextureParameters(FRDGBuilder& GraphBuilder, TRDGUniformBufferRef<FSceneTextureUniformParameters> SceneTextureUniformBuffer)
{
	FSceneTextureParameters Parameters;
	Parameters.SceneDepthTexture = (*SceneTextureUniformBuffer)->SceneDepthTexture;
	if (Parameters.SceneDepthTexture)
	{
		Parameters.SceneStencilTexture = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::CreateWithPixelFormat(Parameters.SceneDepthTexture, PF_X24_G8));
	}
	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;
	// Celshading Lucas: Get Celshading scene texture
	// 셀쉐이딩 장면 텍스처 가져오기
	Parameters.GBufferCelshadingTexture = (*SceneTextureUniformBuffer)->GBufferCelshadingTexture;
	return Parameters;
}

이제 새로운 텍스처를 사용할 수 있고 초기화되었습니다. 이제 GbufferCelshading 을 생성하고 초기화해야 합니다 .

GBufferCelshading 생성 및 초기화

먼저, GBufferCelshadingTexture 에서 참조하는 RDG 텍스처를 생성해야 합니다 . SceneTextures.h 의 FSceneTextures

클래스로 이동하여 GBufferCelshading 멤버를 선언 해야 합니다 .

// (Deferred) Textures containing geometry information for deferred shading.
	FRDGTextureRef GBufferA{};
	FRDGTextureRef GBufferB{};
	FRDGTextureRef GBufferC{};
	FRDGTextureRef GBufferD{};
	FRDGTextureRef GBufferE{};
	FRDGTextureRef GBufferF{};
	FRDGTextureRef GBufferCelshading{}; // Celshading Lucas: create the RDG Texture

 

우리는 이미 GBufferCelshadingTexture 에 대한 참조를 이전에 설정했습니다.

하지만 ESceneTextureSetupMode 구조체에는 여전히 오류가 있습니다  . 그럼 거기에도 셀쉐이딩 GBuffer를 선언해 봅시다. 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,
	GBufferCelshading = 1 << 9, // Celshading Lucas: Append celshading gbuffer to scene texture setup mode
	SSAO = 1 << 10,
	CustomDepth = 1 << 11,
	GBuffers = GBufferA | GBufferB | GBufferC | GBufferD | GBufferE | GBufferF | GBufferCelshading,
	All = SceneColor | SceneDepth | SceneVelocity | GBuffers | SSAO | CustomDepth
};
ENUM_CLASS_FLAGS(ESceneTextureSetupMode);

 

GBufferF  와 SSAO 사이에 GbufferCelshading  플래그를 설정합니다 . 그리고 GBuffers  플래그 끝에 추가하세요 .

이제 SceneRendering.h 파일의 FFastVramConfig 구조체 내부 에 이 버퍼에 대해 빠른 VRAM을 사용할지 여부를 결정하는 플래그를 추가합니다.

struct FFastVramConfig
{
	FFastVramConfig();
	void Update();
	void OnCVarUpdated();
	void OnSceneRenderTargetsAllocated();

	ETextureCreateFlags GBufferA;
	ETextureCreateFlags GBufferB;
	ETextureCreateFlags GBufferC;
	ETextureCreateFlags GBufferD;
	ETextureCreateFlags GBufferE;
	ETextureCreateFlags GBufferF;
	ETextureCreateFlags GBufferVelocity;
	// Celshading Lucas: enable a flag for using fast vram for this gbuffer texture
	//이 gbuffer 텍스처에 대해 빠른 vram을 사용하기 위한 플래그를 활성화합니다.
	ETextureCreateFlags GBufferCelshading;

	// [...]

}

 

SceneRendering.cpp 파일로 돌아갑니다 . 빠른 VRAM을 사용하고 있는지 여부를 확인하기 위해 GBufferCelshading 에 CVAR을 추가합니다 . 기본적으로는 그렇지 않습니다. 이는 플랫폼마다 다르기 때문에 나중에 프로젝트에서 설정합니다.

#define FASTVRAM_CVAR(Name,DefaultValue) static TAutoConsoleVariable<int32> CVarFastVRam_##Name(TEXT("r.FastVRam."#Name), DefaultValue, TEXT(""))

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);
// Celshading Lucas: Create fast VRAM CVAR and assign it to 0 (false)
//빠른 VRAM CVAR을 생성하고 0(false)으로 할당
FASTVRAM_CVAR(GBufferCelshading, 0);
// [...]

 

이제 전역 GBufferCelshading 멤버가 생성되고 초기화되었지만 여전히 변경할 파일이 많습니다. 나는 그 기능이 무엇인지 정말로 파헤치지 않습니다. 그러나 문제를 피하기 위해 거기에 추가하는 것이 좋습니다. 가상 프로덕션의 경우 TextureShareSceneViewExtension.cpp 파일에 FTextureShareSceneViewExtension::ShareSceneViewColors_RenderThread() 함수가 있습니다 . 그리고 TextureShareStrings::SceneTextures 구조체 , TextureShareString.h 파일에서 이를 선언합니다 .

TextureShareString.h 파일의 TextureShareStrings 내부를 다음과 같이 수정.

namespace TextureShareStrings
{
	namespace 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 GBufferCelshading = TEXT("GBufferCelshading");

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

 

TextureShareSceneViewExtension.cpp 파일에  FTextureShareSceneViewExtension::ShareSceneViewColors_RenderThread() 함수에도 다음과 같이 추가.

AddShareTexturePass(TextureShareStrings::SceneTextures::GBufferCelshading, SceneTextures.GBufferCelshading);

 

사후 프로세스 검사기의 경우 PostProcessBufferInspector.cpp 파일에서 FPixelInspectorParameters 구조체에 멤버를 추가  하고 ProcessPixelInspectorRequests() 함수에 설정합니다 .

BEGIN_SHADER_PARAMETER_STRUCT(FPixelInspectorParameters, )
	RDG_TEXTURE_ACCESS(GBufferA, ERHIAccess::CopySrc)
	RDG_TEXTURE_ACCESS(GBufferB, ERHIAccess::CopySrc)
	RDG_TEXTURE_ACCESS(GBufferC, ERHIAccess::CopySrc)
	RDG_TEXTURE_ACCESS(GBufferD, ERHIAccess::CopySrc)
	RDG_TEXTURE_ACCESS(GBufferE, ERHIAccess::CopySrc)
	RDG_TEXTURE_ACCESS(GBufferF, ERHIAccess::CopySrc)
	RDG_TEXTURE_ACCESS(SceneColor, ERHIAccess::CopySrc)
	RDG_TEXTURE_ACCESS(SceneColorBeforeTonemap, ERHIAccess::CopySrc)
	RDG_TEXTURE_ACCESS(SceneDepth, ERHIAccess::CopySrc)
	RDG_TEXTURE_ACCESS(OriginalSceneColor, ERHIAccess::CopySrc)
	// Celshading Lucas: add a copy of gbuffer celshading to pixel inspector (?)
	// 픽셀 검사기에 gbuffer 셀쉐이딩 사본을 추가합니다(?)
	RDG_TEXTURE_ACCESS(GBufferCelshading, ERHIAccess::CopySrc)
END_SHADER_PARAMETER_STRUCT()

 

ProcessPixelInspectorRequests() 함수 내부에 다음의 줄 추가.

// Celshading Lucas: copy the scene texture and append it to the DestinationBuffer
// 장면 텍스처를 복사하여 DestinationBuffer에 추가합니다.
if (Parameters.GBufferCelshading)
{
	FRHITexture* SourceBufferCelshading = Parameters.GBufferCelshading->GetRHI();
	if (DestinationBufferBCDEF->GetFormat() == SourceBufferCelshading->GetFormat())
	{
		FRHICopyTextureInfo CopyInfo;
		CopyInfo.SourcePosition = SourcePoint;
		CopyInfo.DestPosition = FIntVector(4, 0, 0);
		CopyInfo.Size = FIntVector(1, 1, 1);
		RHICmdList.CopyTexture(SourceBufferCelshading, DestinationBufferBCDEF, CopyInfo);
	}
}

 

GBuffer 생성 수정

이제 우리는 Gbuffer에 필요한 모든 것을 만들었습니다. 그 세대를 파헤쳐 보자.

먼저, GBufferInfo.h 파일 내의 FGbufferBindings  구조체에 GBufferCelshading  바인딩을 추가해야 합니다 .

// Describes the bindings of the GBuffer for a given layout
struct FGBufferBindings
{
	FGBufferBinding GBufferA;
	FGBufferBinding GBufferB;
	FGBufferBinding GBufferC;
	FGBufferBinding GBufferD;
	FGBufferBinding GBufferE;
	FGBufferBinding GBufferVelocity;
	FGBufferBinding GBufferCelshading;
};

추가!

 

FGBufferParams 구조체와 함께 이는 기본 패스 텍스처의 할당 및 슬롯 지정을 제어하는 데 사용됩니다.  FGBufferParams  에는 사용된 플랫폼, 속도, 탄젠트, 정적 조명 활성화 등의 레이아웃 매개변수가 포함되어 있습니다.

이제 SceneTextures.cpp 파일의  getter FSceneTextures::GetGBufferRenderTargets() 함수 에 바인딩을 추가해야 합니다. 그러나 또한 동일한 파일에서 마지막 에 FSceneTextures::InitializeViewFamily() 함수를 검색하고  GBufferCelshading 이 하나의 셰이딩 모델에 바인딩된 경우 RDG 텍스처를 만들어야 합니다.

uint32 FSceneTextures::GetGBufferRenderTargets(
	TStaticArray<FTextureRenderTargetBinding,
	MaxSimultaneousRenderTargets>& RenderTargets,
	EGBufferLayout Layout) const
{
//[...]
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("GBufferCelshading"), GBufferCelshading, Bindings.GBufferCelshading.Index }
};
void FSceneTextures::InitializeViewFamily(FRDGBuilder& GraphBuilder, FViewFamilyInfo& ViewFamily)
{
	//[...]
	// Celshading Lucas: create our celshading Gbuffer RDG texture with all parameters set before.
	// 이전에 설정된 모든 매개변수를 사용하여 셀쉐이딩 Gbuffer RDG 텍스처를 생성합니다
	if (Bindings.GBufferCelshading.Index >= 0)
	{
		const FRDGTextureDesc Desc(FRDGTextureDesc::Create2D(Config.Extent, Bindings.GBufferCelshading.Format, FClearValueBinding::Transparent, Bindings.GBufferCelshading.Flags | FlagsToAdd | GFastVRamConfig.GBufferCelshading));
		SceneTextures.GBufferCelshading = GraphBuilder.CreateTexture(Desc, TEXT("GBufferCelshading"));
	}
	// [...]
}

 

GBufferInfo.h 로 돌아가서 EGBufferSlot 열거형에서 GBS_num  바로 앞에 셀쉐이딩 슬롯을 설정했습니다  .

enum EGBufferSlot
{
	GBS_Invalid,
	GBS_SceneColor, // RGB 11.11.10
	GBS_WorldNormal, // RGB 10.10.10
	GBS_PerObjectGBufferData, // 2
	GBS_Metallic, // R8
	GBS_Specular, // R8
	GBS_Roughness, // R8
	GBS_ShadingModelId, // 4 bits
	GBS_SelectiveOutputMask, // 4 bits
	GBS_BaseColor, // RGB8
	GBS_GenericAO, // R8
	GBS_IndirectIrradiance, // R8
	GBS_AO, // R8
	GBS_Velocity, // RG, float16
	GBS_PrecomputedShadowFactor, // RGBA8
	GBS_WorldTangent, // RGB8
	GBS_Anisotropy, // R8
	GBS_CustomData, // RGBA8, no compression
	GBS_SubsurfaceColor, // RGB8
	GBS_Opacity, // R8
	GBS_SubsurfaceProfile, //RGB8
	GBS_ClearCoat, // R8
	GBS_ClearCoatRoughness, // R8
	GBS_HairSecondaryWorldNormal, // RG8
	GBS_HairBacklit, // R8
	GBS_Cloth, // R8
	GBS_SubsurfaceProfileX, // R8
	GBS_IrisNormal, // RG8
	GBS_SeparatedMainDirLight, // RGB 11.11.10
	GBS_Celshading, // Celshading Lucas: R8 slot
	GBS_Num
};

 

Gbuffer 슬롯은 텍스처 채널 및 비트 패킹을 관리하는 방법을 결정합니다. 그리고 셰이딩 모델의 경우 이는 " 이 셰이딩 모델이 이 슬롯에 씁니다 " 라고 말하는 데 사용됩니다 . 슬롯이 사용되지 않으면 이전에 gbuffer 이론 장에서 본 것처럼 폐기하십시오.

ShaderGenerationUtil.cpp 내에서 GetSlotTextName() 함수 의 스위치 끝에 이 슬롯을 추가합니다 . 이는 이전 장에서 본 HLSL 구조체 GBufferData  의 멤버 이름이 됩니다 .

static FString GetSlotTextName(EGBufferSlot Slot)
{
	FString Ret = TEXT("");
	switch (Slot)
	{
	case GBS_Invalid:
		check(0);
		return TEXT("Invalid");
	case GBS_SceneColor:
		return TEXT("SceneColor");
	case GBS_WorldNormal:
		return TEXT("WorldNormal");
	case GBS_PerObjectGBufferData:
		return TEXT("PerObjectGBufferData");
	case GBS_Metallic:
		return TEXT("Metallic");
	case GBS_Specular:
		return TEXT("Specular");
	case GBS_Roughness:
		return TEXT("Roughness");
	case GBS_ShadingModelId:
		return TEXT("ShadingModelID");
	case GBS_SelectiveOutputMask:
		return TEXT("SelectiveOutputMask");
	case GBS_BaseColor:
		return TEXT("BaseColor");
	case GBS_GenericAO:
		return TEXT("GenericAO");
	case GBS_IndirectIrradiance:
		return TEXT("IndirectIrradiance");
	case GBS_Velocity:
		return TEXT("Velocity");
	case GBS_PrecomputedShadowFactor:
		return TEXT("PrecomputedShadowFactors");
	case GBS_WorldTangent:
		return TEXT("WorldTangent");
	case GBS_Anisotropy:
		return TEXT("Anisotropy");
	case GBS_CustomData:
		return TEXT("CustomData");
	case GBS_SubsurfaceColor:
		return TEXT("SubsurfaceColor");
	case GBS_Opacity:
		return TEXT("Opacity");
	case GBS_SubsurfaceProfile:
		return TEXT("SubsurfaceProfile");
	case GBS_ClearCoat:
		return TEXT("ClearCoat");
	case GBS_ClearCoatRoughness:
		return TEXT("ClearCoatRoughness");
	case GBS_HairSecondaryWorldNormal:
		return TEXT("HaireEcondaryWorldNormal");
	case GBS_HairBacklit:
		return TEXT("HairBacklit");
	case GBS_Cloth:
		return TEXT("Cloth");
	case GBS_SubsurfaceProfileX:
		return TEXT("SubsurfaceProfileX");
	case GBS_IrisNormal:
		return TEXT("IrisNormal");
	case GBS_SeparatedMainDirLight:
		return TEXT("SeparatedMainDirLight");
	// Celshading Lucas: This is the name this slot use in the HLSL struct GBufferData
	// 이것은 HLSL 구조체 GBufferData에서 이 슬롯이 사용하는 이름입니다.
	case GBS_Celshading:
		return TEXT("Celshading");
	default:
		break;
	};

	return TEXT("ERROR");
}

 

이제 가장 어려운 부분을 바꿀 차례입니다. FetchLegacyGBufferInfo() 함수의 GBufferInfo.cpp 파일로 이동해 보겠습니다 .

먼저, 인덱스 -1(사용되지 않음)에서 GbufferCelshading을  초기화합니다 . 나중에 GBuffer 구성에 따라 실제 인덱스를 설정합니다.

FGBufferInfo RENDERCORE_API FetchLegacyGBufferInfo(const FGBufferParams& Params)
{
	FGBufferInfo Info = {};
 
	check(!Params.bHasVelocity || !Params.bHasTangent);
 
	bool bStaticLighting = Params.bHasPrecShadowFactor;
 
	int32 TargetLighting = 0;
	int32 TargetGBufferA = 1;
	int32 TargetGBufferB = 2;
	int32 TargetGBufferC = 3;
	int32 TargetGBufferD = -1;
	int32 TargetGBufferE = -1;
	int32 TargetGBufferF = -1;
	int32 TargetVelocity = -1;
	int32 TargetCelshading = -1;
	int32 TargetSeparatedMainDirLight = -1;
 
// [...]

그런 다음 Gbuffer에 포함된 최대 대상을 설정하기 위한 if 조건이 있습니다. 새 항목을 추가했으므로 숫자를 1씩 늘려야 합니다.

if (Params.bHasVelocity == 0 && Params.bHasTangent == 0)
	{
		//Info.NumTargets = Params.bHasPrecShadowFactor ? 7 : 6;
		Info.NumTargets = Params.bHasPrecShadowFactor ? 6 : 5;
	}
	else
	{
		//Info.NumTargets = Params.bHasPrecShadowFactor ? 8 : 7;
		Info.NumTargets = Params.bHasPrecShadowFactor ? 7 : 6;
	}

주석으로 추가는했는데 바꾸지 않았따. 빌드를 하니까 추가된 내용에 대해서는 지들이 알아서 숫자를.. 늘려주진 않을텐데 암튼 권장하는 방식으로 했음..

 

 

이 아래에서 마침내 GBuffer와 해당 매개변수에 대한 MRT 인덱스를 설정합니다. 방금 CustomData  매개변수를 복사했습니다 . 이전에 GbufferCelshading을 추가했으므로 TargetSeparatedMainDirLight  및 TargetGBufferE를  증가시키는 것을 잊지 마십시오 .

	if (Params.bHasVelocity == 0 && Params.bHasTangent == 0)
	{
		TargetGBufferD = 4;
		TargetCelshading = 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("GBufferCelshading"), 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;
		TargetCelshading = 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("GBufferCelshading"), 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;
		}
	}
	else if (Params.bHasTangent)
	{
		TargetGBufferF = 4;
		TargetGBufferD = 5;
		TargetCelshading = 6;

		Info.Targets[4].Init(GBT_Unorm_8_8_8_8,  TEXT("GBufferF"), false,  true,  true,  true);
		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("GBufferCelshading"), 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, true);
			TargetSeparatedMainDirLight = 8;
		}
	}

 

 

그리고 마지막에는 슬롯을 위한 비트 패킹이 있습니다. 이는 슬롯이 메모리에 기록되는 방식을 결정합니다. 먼저 FGBufferItem 을 생성하고 버퍼 압축을 설정하고(슬롯은 X 비트의 X 채널을 사용함) 비트 패킹이 짝수, 홀수 또는 둘 다인지 여부를 설정합니다.

셀쉐이딩 정보에는 압축되지 않은 8비트 채널 하나만 있으면 됩니다. 그런 다음 채널별로 패킹을 설정합니다.

2개의 값을 전달하면 전체 채널을 사용한다는 의미입니다. 4개의 값을 전달하면 비트도 팩해야 한다는 의미입니다.

비트 패킹에 대한 자세한 내용은 다른 슬롯, 특히 함께 패킹되는 GBS_ShadingModelId / GBS_SelectiveOutputMask 를 살펴보세요.

// 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);

	// Celshading Lucas: set slot bit packing
	Info.Slots[GBS_Celshading] = FGBufferItem(GBS_Celshading, GBC_Raw_Unorm_8, GBCH_Both);
	Info.Slots[GBS_Celshading].Packing[0] = FGBufferPacking(TargetCelshading, 0, 3);

GBufferD 아래쪽에 비트패킹 추가..

 

GBuffer 최대 타겟

GBuffer가 갖는 최대 렌더 타겟 수는 C++ 및 HLSL로 하드 코딩되어 있습니다. 내 구성에서는 정적 조명/미리 계산된 그림자를 사용하지 않으므로 하나의 렌더 타겟을 사용할 수 있습니다. 모두 필요한 경우 이 숫자를 늘려야 할 수도 있습니다.

GBufferInfo.h  파일에서 FGBufferInfo  구조체에는  정적 const  MaxTargets  멤버가 있습니다 .

struct FGBufferInfo
{
	// Increase this if in need of more GBuffer render target.
	static const int MaxTargets = 8;

	int32 NumTargets;
	FGBufferTarget Targets[MaxTargets];

	FGBufferItem Slots[GBS_Num];

};

 

이렇게 하면 GBuffer를 변경하기 위한 C++에서의 작업이 종료된다.

다음은 HLSL쪽에서의 변경이 있을 예정이다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함