[DirectX 11] Deferred Rendering GBuffer

2021. 12. 14. 06:07·Graphics

Deferred Rendering

 

Rendering 방식

- Forward의 경우한개의 RenderTarget을 사용하여 각각의 오브젝트를 각각 라이트 연산을 하는 방식.

- Deferred는 여러개의 RenderTarget을 사용하여 각각의 오브젝트를 해당 RenderTarget에 데이터를 저장해논 후 최종 라이트  연산을 한번에 하는 방식이 있다.

 

Deferred의 이점

- 라이트의 개수가 많아질수록 이득이 크다. 예를들어 Forward Rendereing의 경우 라이트가 10개라고 생각할 경우 각각 오브젝트      마다 라이트연산을 n*10 만큼의 비용이 소모된다. 하지만 Deferred Rendering의 경우 화면크기의 RenderTarget들에 각각 필요 한 데이터 (Position, Normal, Material ...)들을 픽셀별로 저장하고 있어 최종적인 Light 연산 10번을 통해 화면에  비추어지는 라이트 연산을 할수 있다.

 

Deferred의 단점

- 오브젝트간의 Alpha 선후관계가 처리하기 복잡해진다. 해결 방법으론 알파 레이어를 따로 쌓아서 처리하는 방식을 주로 사용한다고 하는데 추후에 변경해야 할 사항이다.

 

Albedo GBuffer
Normal (World) GBuffer
Position (World), Material ID GBuffer
Shadow Position GBuffer
Normal (View), Position (View) GBuffer

 

현재 Renderer에서 사용하고 있는 GBuffer는 위와 같은 데이터를 사용하여 5개의 RenderTarget에 각각의 정보를 저장한 후

Light Pass에서 위의 RenderTarget Shader Resource View를 받아 최종 Light 연산을 한다.

 

GBuffer 설정시 주의점

- 모든 채널을 효율적으로 모두 사용하여 최소한의 RenderTarget을 사용하는 것이 제일 중요할 것이다.

- Rendering 과정에서 Albedo를 찍어야하는 RenderTarget을 제외하고 나머지는 1.0 이상의 값이 들어가야 하기 때문에  Format을 R8G8B8A8을 사용하면 안된다. Float형으로 저장하는 것에 유의.

- Albedo Map에 Alpha값이 들어가 있을경우가 있기 때문에 해당 RenderTarget은 Blend State를 Alpha Blend Mode로 변경해주어야 하는데 처음엔 한개의 RenderTarget만 설정할 수 있는지 모르고 전체 RenderTarget의 Alpha 값을 1.0으로 고정해두고 했었다(정말 절대로 하면 안되는 방식) 정말 말도 안되는 방식이라 생각하여 추후엔 해당 Albedo RenderTarget만 Blending Option을 주는 방식으로 변경하여 나머지 RenderTarget Alpha 값도 데이터를 넣어 사용하는 방식으로 변경하였다.

- Object Material Data를 어떻게 넣어줄지 고민이 됬었는데, RenderTarget을 사용하여 데이터를 넘기기엔 너무 많은 데이터가 있어 문제였다. 그래서 고안한 방법은 오브젝트별로 Material Data가 추가될때 마다 Index를 매겨서 해당 Material Index를 통해 데이터를 접근하는 방식으로 생각했다. 모든 Material Data List는 Light 연산시 Constant Buffer에 올려 둔다.

/// Texture 2D
// Albedo 전용 Texture 2D 
D3D11_TEXTURE2D_DESC texDescDiffuse;
ZeroMemory(&texDescDiffuse, sizeof(texDescDiffuse));
texDescDiffuse.Width = width;
texDescDiffuse.Height = height;
texDescDiffuse.MipLevels = 1;
texDescDiffuse.ArraySize = 1;
texDescDiffuse.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
texDescDiffuse.SampleDesc.Count = 1;
texDescDiffuse.SampleDesc.Quality = 0;
texDescDiffuse.Usage = D3D11_USAGE_DEFAULT;
texDescDiffuse.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
texDescDiffuse.CPUAccessFlags = 0;
texDescDiffuse.MiscFlags = 0;

// Pixel Data 전용 Texture 2D
D3D11_TEXTURE2D_DESC texDescPosNormal;
ZeroMemory(&texDescPosNormal, sizeof(texDescPosNormal));
texDescPosNormal.Width = width;
texDescPosNormal.Height = height;
texDescPosNormal.MipLevels = 1;
texDescPosNormal.ArraySize = 1;
texDescPosNormal.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
texDescPosNormal.SampleDesc.Count = 1;
texDescPosNormal.SampleDesc.Quality = 0;
texDescPosNormal.Usage = D3D11_USAGE_DEFAULT;
texDescPosNormal.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
texDescPosNormal.CPUAccessFlags = 0;
texDescPosNormal.MiscFlags = 0;

/// RenderTargetView 2D
D3D11_RENDER_TARGET_VIEW_DESC rtvDescDiffuse;
ZeroMemory(&rtvDescDiffuse, sizeof(rtvDescDiffuse));
rtvDescDiffuse.Format = texDescDiffuse.Format;
rtvDescDiffuse.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtvDescDiffuse.Texture2D.MipSlice = 0;

D3D11_RENDER_TARGET_VIEW_DESC rtvDescPosNormal;
ZeroMemory(&rtvDescPosNormal, sizeof(rtvDescPosNormal));
rtvDescPosNormal.Format = texDescPosNormal.Format;
rtvDescPosNormal.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
rtvDescPosNormal.Texture2D.MipSlice = 0;

/// ShaderResourceView 2D
D3D11_SHADER_RESOURCE_VIEW_DESC srvDescDiffuse;
ZeroMemory(&srvDescDiffuse, sizeof(srvDescDiffuse));
srvDescDiffuse.Format = texDescDiffuse.Format;
srvDescDiffuse.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDescDiffuse.Texture2D.MostDetailedMip = 0;
srvDescDiffuse.Texture2D.MipLevels = 1;

D3D11_SHADER_RESOURCE_VIEW_DESC srvDescPosNormal;
ZeroMemory(&srvDescPosNormal, sizeof(srvDescPosNormal));
srvDescPosNormal.Format = texDescPosNormal.Format;
srvDescPosNormal.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvDescPosNormal.Texture2D.MostDetailedMip = 0;
srvDescPosNormal.Texture2D.MipLevels = 1;

RenderTarget GBuffer Format 설정 방식.

 

	D3D11_BLEND_DESC blendDesc;
	ZeroMemory(&blendDesc, sizeof(blendDesc));
	blendDesc.AlphaToCoverageEnable = TRUE;
	blendDesc.IndependentBlendEnable = TRUE;
	blendDesc.RenderTarget[0].BlendEnable = TRUE;
	blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
	blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
	blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
	blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
	blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
	blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
	blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
	blendDesc.RenderTarget[1].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
	blendDesc.RenderTarget[2].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
	blendDesc.RenderTarget[3].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
	blendDesc.RenderTarget[4].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

RenderTarget GBuffer BlendState 설정 방식.

 

struct PixelOut
{
    float4 Albedo   : SV_Target0;
    float4 Normal   : SV_Target1;
    float4 Position : SV_Target2;
    float4 Shadow   : SV_Target3;
    float4 Depth    : SV_Target4;
};

PixelOut Deferred_PS(VertexIn pin)
{
    PixelOut vout;

    ...
    
    vout.Albedo = albedo;
    vout.Normal = float4(normalW, gamma);
    vout.Position = float4(pin.PosW, gMatID);
    vout.Shadow = float4(pin.ShadowPosH.xyz, 0.0f);
    vout.Depth = float4(normalV, pin.PosV.z);
    
    return vout;
}

Obejct Deferred Rendering Pixel Shader 출력 방식.

 

cbuffer cbLight : register(b1)
{
    DirectionalLight gDirLights;
    PointLight gPointLights[5];
    SpotLight gSpotLights[5];
    Material gMaterials[5];
};

float4 Light_PS(VertexIn pin) : SV_TARGET
{
    ...
    
    // 현재 픽셀의 Material ID..
    uint matID = round(position.w);
    
    // Directional Light
    ComputeDirectionalLight(gMaterials[matID], gDirLights, float3(normal.xyz), ViewDirection,
			A, D, S);

    ambient += ambientAccess * A;
    diffuse += shadows * D;
    spec += shadows * S;
    
    ...
    
    litColor = albedo * (ambient + diffuse) + spec;
    
    // Common to take alpha from diffuse material and texture.
    litColor.a = gMaterials[matID].Diffuse.a * albedo.a;
    
    return litColor;
}

Object Material 적용 방식.

'Graphics' 카테고리의 다른 글

[DirectX 11] Skinning Mesh  (0) 2021.12.18
[DirectX 11] Normal Mapping  (0) 2021.12.18
[DirectX 11] Gamma Correction  (0) 2021.12.18
[DirectX 11] Shadow Map  (0) 2021.12.14
[DirectX 11] Screen Space Ambient Occlusion  (0) 2021.12.14
'Graphics' 카테고리의 다른 글
  • [DirectX 11] Normal Mapping
  • [DirectX 11] Gamma Correction
  • [DirectX 11] Shadow Map
  • [DirectX 11] Screen Space Ambient Occlusion
KyuHwang
KyuHwang
  • KyuHwang
    DirectX Engine
    KyuHwang
  • 전체
    오늘
    어제
    • 분류 전체보기 (50)
      • C++ (4)
      • CS (0)
      • Graphics (32)
      • DLL (2)
      • Shader (7)
      • Project (4)
      • ETC (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • YouTube
  • 공지사항

  • 인기 글

  • 태그

    animation retargeting
    std::enable_if
    bc format
    DLL Interface
    RunTime Compile Shader
    Explicit Linking
    DirectX 2D
    texture block compression
    Project
    animation constraint
    Return Type Operator
    rigging chain
    C ++
    Define Function
    Shader Reflection
    hlsl
    Win API
    Alpha Blending
    Define Macro
    nvtt
    Directx11
    shader
    Implicit Linking
    Order Independent Transparency
    Shader Resource 관리
    Hash Code
    dll
    std::is_base_of
    Shader Macro
    mobile format
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
KyuHwang
[DirectX 11] Deferred Rendering GBuffer
상단으로

티스토리툴바