개발 일자 : 2022년 1월 20일
기존에 렌더 타겟들을 정수형 버퍼로 사용하고 있었다가, 더 넓은 색감을 지원하고자 HDR을 지원하도록 변경하였습니다.
이를 위해, 렌더 타겟 생성 시에 16bit 실수형 포맷으로 세팅해줬습니다.
기존 렌더링 방식을 그대로 사용하여 16bit 실수형 버퍼에 기록하고, 마지막에 ToneMapping을 하여 HDR->LDR로 압축해줍니다. 이유는, 디스플레이는 HDR 영역까지 표현할 수 없기 때문에 0 ~ 1.0으로 맵핑해줘야하기 때문입니다. 제가 구현해본 ToneMapping은 두 가지입니다.
1. Reinhard
가장 기본적인 톤 맵퍼입니다. 톤 매핑이 끝난 후에는 Gamma Correction을 위해 2.2 제곱 해줬던 값을 다시 1/2.2 제곱을 해주고 있습니다.
float4 PS_ToneMapping_Reinhard(VertexOut pin) : SV_Target
{
float4 color = gInput.Sample(samLinear, pin.Tex);
float k = 1.0f;
color.xyz = color.xyz / (color.xyz + k);
// 라이트 연산 및 톤 매핑이 끝났으므로 다시 Encoding 공간으로 보낸다.
color = pow(color, 1 / 2.2f);
return color;
}
2. ACES Filmic
ACES Filmic 톤 맵퍼는 언리얼 엔진4에서 사용되었다고하여 구현해봤습니다. Reinhard에 비해 어두운 부분은 더 어둡게, 밝은 부분은 더 밝게 처리하여 마치 영화 필름같은 느낌을 낼 수 있습니다. 가장 위 그림에서 보시는 화면이 ACES Filmic 톤 매핑을 적용한 화면입니다.
float4 PS_ToneMapping_ACES_Filmic(VertexOut pin) : SV_Target
{
float3 color = gInput.Sample(samLinear, pin.Tex).xyz;
float a = 2.51f;
float b = 0.03f;
float c = 2.43f;
float d = 0.59f;
float e = 0.14f;
color = saturate((color * (a * color + b)) / (color * (c * color + d) + e));
// 라이트 연산 및 톤 매핑이 끝났으므로 다시 Encoding 공간으로 보낸다.
color = pow(color, 1 / 2.2f);
return float4(color.xyz, 1.0f);
}
ToneMapper 클래스에서는 원하는 톤 매핑 타입을 선택할 수 있도록 하였습니다.
마지막으로 HDR, ToneMapping을 구현하면서 알게된 점은 그래픽스 엔진에서 기본 Anti-Aliasing을 FXAA로 사용하고 있었는데 FXAA가 LDR에서 최적화되어 있다는 사실이었습니다. 따라서 FXAA의 순서를 톤 매핑 다음으로 변경해주었습니다.
'DirectX 자체엔진 개발' 카테고리의 다른 글
[DirectX 11] Normal Mapping (0) | 2022.04.17 |
---|---|
[DirectX 11] Skinning Animation (0) | 2022.04.16 |
[DirectX 11] 외곽선 (0) | 2022.04.14 |
[DirectX 11] 파티클 시스템 (0) | 2022.03.18 |
[DirectX 11] Emissive (0) | 2022.03.14 |