PostProcess
현재 DepthStencilView를 ShaderResourceView로 사용
렌더링이 다 끝난 시점에 Quad에 그려낸다
Quad
VS_OUT mainVS(uint id : SV_VertexID)
{
VS_OUT output;
// 풀스크린 쿼드 정점 위치 (Triangle Strip 용)
float2 pos[4] =
{
float2(-1, 1), // LT
float2(1, 1), // RT
float2(-1, -1), // LB
float2(1, -1) // RB
};
float2 uv[4] =
{
float2(0, 0),
float2(1, 0),
float2(0, 1),
float2(1, 1)
};
// 수정된 position 계산 (z=0, w=1 중요!)
output.position = float4(pos[id], 0.0, 1.0);
output.uv = uv[id];
return output;
}
각 픽셀의 depth 수치 계산
float4 mainPS(VS_OUT input) : SV_Target
{
float depth = SceneDepthTex.Sample(PointSampler, input.uv).r;
if (depth == 1.0)
{
return float4(0, 0, 0, 1);
}
float linearDepth = (NearPlane * FarPlane) / (FarPlane - depth * (FarPlane - NearPlane));
float normalized = saturate((linearDepth - NearPlane) / (FarPlane - NearPlane));
float expo = 1 - exp(-normalized * 5.0); // 5.0은 조정 가능한 falloff 계수
return float4(expo, expo, expo, 1.0);
}
SceneDepthTex
기존 FrameBuffer의 Back buffer를 텍스처로 사용하여 해당 텍스처 위에 Quad로 Fog를 그리는 방식으로 구현
원래 화면의 Pixel 색상과 Fog Quad의 색상 값을 interpolation 하도록 한다.
// Backbuffer를 RenderTargetTexture에 복사해 놓는 내용
void FGraphicsDevice::CreateSceneColorResources()
{
ID3D11Texture2D* backBuffer = nullptr;
HRESULT hr = SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBuffer);
if (FAILED(hr) || backBuffer == nullptr)
return;
D3D11_TEXTURE2D_DESC backBufferDesc;
backBuffer->GetDesc(&backBufferDesc);
...
hr = Device->CreateShaderResourceView(RenderTargetTexture, &srvDesc, &SceneColorSRV);
DeviceContext->CopyResource(RenderTargetTexture, backBuffer);
DeviceContext->OMSetRenderTargets(1, &FrameBufferRTV, DepthStencilView);
backBuffer->Release();
}
복사해놓은 backbuffer texture를 SRV로 만들고 이를 PS에 전달하여 사용
Graphics->DeviceContext->PSSetShaderResources(5, 1, &Graphics->SceneColorSRV);
PS shader
float4 mainPS(VS_OUT input) : SV_TARGET
{
// 전달한 백버퍼 텍스처와 DepthTexture를 샘플링
float4 sceneColor = SceneTexture.Sample(SamplerLinear, input.uv);
float depth = DepthTexture.Sample(SamplerLinear, input.uv).r;
// Camera로 부터 Depth 정규화 및 Height를 위한 높이값 변환
float linearDepth = (NearPlane * FarPlane) / (FarPlane - depth * (FarPlane - NearPlane));
float normalized = saturate((linearDepth - DistanceFogNear) / (DistanceFotFar - DistanceFogNear));
float3 worldPosition = ReconstructWorldPosition(input.uv, depth);
// 높이 기반 안개 계산 - Exponential way
float heightDiff = saturate((HeightFogEnd - worldPosition.z) / (HeightFogEnd - HeightFogStart));
float heightFactor = saturate(1.f - exp(-heightDiff * 3.0f));
// 정규화된 깊이 값을 사용하여 거리 기반 안개 계산 (from debug depth shader)
float distanceFactor;
// Mode에 따라 Exponent를 사용할 지 정규화된 깊이를 그대로 사용할 지 결정
if (IsExponential != 0)
{
distanceFactor = saturate(1.f - exp(-normalized * 5.0));
}
else
{
distanceFactor = normalized;
}
float fogFactor = FogDensity * heightFactor * distanceFactor;
...
float3 baseInscattering = InscatteringColor.rgb;
float3 fogColor = baseInscattering + directionalInscattering;
// 최종 결정된 Fogfactor를 기반으로 Backbuffer texture와 Fog Color를 interpolation
return float4(lerp(sceneColor.rgb, fogColor, fogFactor), sceneColor.a);
}