Deferred Rendering
Rendering 방식
- Forward의 경우한개의 RenderTarget을 사용하여 각각의 오브젝트를 각각 라이트 연산을 하는 방식.
- Deferred는 여러개의 RenderTarget을 사용하여 각각의 오브젝트를 해당 RenderTarget에 데이터를 저장해논 후 최종 라이트 연산을 한번에 하는 방식이 있다.
Deferred의 이점
- 라이트의 개수가 많아질수록 이득이 크다. 예를들어 Forward Rendereing의 경우 라이트가 10개라고 생각할 경우 각각 오브젝트 마다 라이트연산을 n*10 만큼의 비용이 소모된다. 하지만 Deferred Rendering의 경우 화면크기의 RenderTarget들에 각각 필요 한 데이터 (Position, Normal, Material ...)들을 픽셀별로 저장하고 있어 최종적인 Light 연산 10번을 통해 화면에 비추어지는 라이트 연산을 할수 있다.
Deferred의 단점
- 오브젝트간의 Alpha 선후관계가 처리하기 복잡해진다. 해결 방법으론 알파 레이어를 따로 쌓아서 처리하는 방식을 주로 사용한다고 하는데 추후에 변경해야 할 사항이다.
현재 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 적용 방식.
'DirectX 11' 카테고리의 다른 글
[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 |