3D 렌더링 이후에 화면에 다양한 효과를 적용하는 "후처리(Post Processing)"는 게임 그래픽스에서 아주 중요한 파이프라인입니다. 이번 글에서는 이미지 필터 클래스를 활용해 후처리 필터를 구현하는 구조와 개념을 차근차근 살펴보겠습니다.
1. 이미지 필터 클래스 구조
- 다양한 쉐이더를 효율적으로 관리하기 위해 ImageFilter 클래스가 사용됩니다.
- 생성자에서 버텍스/픽셀 쉐이더의 접두사(prefix)를 설정하면 쉐이더 파일명을 자동으로 결정합니다.

2. 후처리용 텍스처 초기화
- 일반 모델 텍스처와 다르게 클램프(Clamp) 모드 사용
- Depth Buffer는 불필요하므로 비활성화
- 이미지 해상도는 자유롭게 조절 가능
- 고품질 처리를 위해 R32G32B32_FLOAT 혹은 128비트 float 포맷 사용
3. View 개념: RTV와 SRV
- RTV(Render Target View): 이 텍스처에 출력(렌더링)
- SRV(Shader Resource View): 쉐이더에서 입력으로 사용
같은 텍스처에 대해 RTV, SRV 두 개의 View를 따로 만들어 사용
4. 렌더링 절차
- 렌더 타겟을 백버퍼 대신 직접 만든 텍스처로 교체
- 사각형(Full-screen Quad)을 그리는 구조
- 쉐이더에서 텍스처 좌표를 사용해 이미지를 처리
필터 구현 순서 예시 (Copy → Final Filter)
- CopyFilter
- 백버퍼의 이미지를 읽어서 새로운 텍스처에 복사
- 픽셀 쉐이더: 단순 샘플링 및 출력
- FinalFilter
- CopyFilter의 결과를 백버퍼로 다시 렌더링
이중 필터 구조는 이후 블룸, 가우시안 블러 등 필터 체인 연결 시 확장 가능
void ExampleApp::BuildFilters() {
m_filters.clear();
// 해상도를 낮춰서 다운 샘플링
auto copyFilter =
make_shared<ImageFilter>(m_device, m_context, L"Sampling", L"Sampling",
m_screenWidth, m_screenHeight);
copyFilter->SetShaderResources({m_shaderResourceView});
m_filters.push_back(copyFilter);
auto downFilter = make_shared<ImageFilter>(
m_device, m_context, L"Sampling", L"Sampling", m_screenWidth / m_down,
m_screenHeight / m_down);
downFilter->SetShaderResources({m_shaderResourceView});
downFilter->m_pixelConstData.threshold = m_threshold;
downFilter->UpdateConstantBuffers(m_device, m_context);
m_filters.push_back(downFilter);
for (int i = 0; i < m_repeat; i++) {
auto &prevResource = m_filters.back()->m_shaderResourceView;
m_filters.push_back(make_shared<ImageFilter>(
m_device, m_context, L"Sampling", L"BlurX", m_screenWidth / m_down,
m_screenHeight / m_down));
m_filters.back()->SetShaderResources({prevResource});
auto &prevResource2 = m_filters.back()->m_shaderResourceView;
m_filters.push_back(make_shared<ImageFilter>(
m_device, m_context, L"Sampling", L"BlurY", m_screenWidth / m_down,
m_screenHeight / m_down));
m_filters.back()->SetShaderResources({prevResource2});
}
auto upFilter =
make_shared<ImageFilter>(m_device, m_context, L"Sampling", L"Sampling",
m_screenWidth, m_screenHeight);
upFilter->SetShaderResources({m_filters.back()->m_shaderResourceView});
m_filters.push_back(upFilter);
auto combineFilter =
make_shared<ImageFilter>(m_device, m_context, L"Sampling", L"Combine",
m_screenWidth, m_screenHeight);
combineFilter->SetShaderResources({copyFilter->m_shaderResourceView,
m_filters.back()->m_shaderResourceView});
combineFilter->SetRenderTargets(
{this->m_renderTargetView}); // 렌더타겟 교체
combineFilter->m_pixelConstData.strength = m_strength;
combineFilter->UpdateConstantBuffers(m_device, m_context);
m_filters.push_back(combineFilter);
}
6. 필터 실행 예시
cpp
복사편집
mFilters.push_back(copyFilter);
mFilters.push_back(finalFilter);
mFilters에 넣어둔 필터들이 렌더 순서대로 실행됨
각 필터는 입력 SRV와 출력 RTV를 세팅하여 체인 구성
- 백버퍼에 3D 씬 렌더링
- → RenderTargetView (RTV)를 통해 렌더링
- → 동시에 같은 텍스처에 대해 ShaderResourceView (SRV)도 생성
- 🧪 후처리용 필터 ① (예: 복사, 블룸 등)
- SRV로 백버퍼 내용을 읽고
- 쉐이더로 효과 적용
- 출력은 새로운 텍스처에 RTV로 저장
- 🔁 후처리용 필터 ②~N
- 이전 필터의 결과 텍스처를 SRV로 사용
- 새로운 효과를 적용하고 또 다른 RTV에 저장
- 🖼️ 마지막 필터 결과 → 다시 백버퍼에 복사(RenderTargetView로 설정)
이렇게 해야 모니터에 출력 가능
요약
✔ 렌더 타겟을 백버퍼 대신 커스텀 텍스처로 변경
✔ 사각형 하나로 전체 화면을 덮고, 쉐이더에서 텍스처를 샘플링
✔ 필터는 입력/출력 텍스처, 쉐이더를 연결해 체인처럼 구성
✔ GUI → 컨스턴트 버퍼 → 쉐이더로 필터 파라미터 실시간 조절 가능
'DX' 카테고리의 다른 글
| Bloom Filter 와 Post-Processing 정리 (0) | 2025.07.13 |
|---|---|
| fresnel 효과 (0) | 2025.07.13 |
| 이미지 기반 라이팅 (0) | 2025.07.13 |
| 환경 매핑(반사 매핑) (0) | 2025.07.13 |
| 큐브 매핑 (0) | 2025.07.13 |