C++ Algorithm & Study/Game Math & DirectX 11

[Direct11] 29. EX App Program - Blur System

GameChoi 2023. 6. 21. 22:09

1. EX App Program

1.1 Blur System

1.1.1 C++ 응용프로그램

void BlurFilter::BlurInPlace(ComPtr<ID3D11DeviceContext> dc,
	ComPtr<ID3D11ShaderResourceView> inputSRV,
	ComPtr<ID3D11UnorderedAccessView> inputUAV,
	int32 blurCount)

 - 계산 셰이더를 실행하여 Render to Texture를 흐림

   - A에 대한 세이더 자원 뷰를 계산 셰이더의 입력, B에 대한 순서 없는 뷰를 계산 셰이더의 출력 설정

     - 스레드 그룹들을 배분해서 수평 흐리기 작업을 수행

D3DX11_TECHNIQUE_DESC techDesc;
Effects::BlurFX->HorzBlurTech->GetDesc(&techDesc);
for (uint32 p = 0; p < techDesc.Passes; ++p)
{
    Effects::BlurFX->SetInputMap(inputSRV);
    Effects::BlurFX->SetOutputMap(_blurredOutputTexUAV);
    Effects::BlurFX->HorzBlurTech->GetPassByIndex(p)->Apply(0, dc.Get());

    uint32 numGroupsX = (uint32)ceilf(_width / 256.0f);
    dc->Dispatch(numGroupsX, _height, 1);
}

   - 자원의 효율적인 관리를 위해 입력 Texture를 계산 셰이더에서 떼어냄

     - 출력 Texture 또한 계산 셰이더에서 떼어냄, 하나의 자원을 동시에 입력과 출력 모두 사용X

ID3D11ShaderResourceView* nullSRV[1] = { 0 }; dc->CSSetShaderResources(0, 1, nullSRV);
ID3D11UnorderedAccessView* nullUAV[1] = { 0 }; dc->CSSetUnorderedAccessViews(0, 1, nullUAV, 0);

   - B에 대한 세이더 자원 뷰를 계산 셰이더의 입력, A에 대한 순서 없는 뷰를 계산 세이더의 출력으로 설정

     - 스레드 그룹들을 배분해서 수직 흐리기 작업을 수행 후 입력, 출력 자원을 떼어냄

Effects::BlurFX->VertBlurTech->GetDesc(&techDesc);
for (uint32 p = 0; p < techDesc.Passes; ++p)
{
    Effects::BlurFX->SetInputMap(_blurredOutputTexSRV);
    Effects::BlurFX->SetOutputMap(inputUAV);
    Effects::BlurFX->VertBlurTech->GetPassByIndex(p)->Apply(0, dc.Get());

    uint32 numGroupsY = (uint32)ceilf(_height / 256.0f);
    dc->Dispatch(_width, numGroupsY, 1);
}
dc->CSSetShaderResources(0, 1, nullSRV); dc->CSSetUnorderedAccessViews(0, 1, nullUAV, 0);
dc->CSSetShader(0, 0, 0); // 비활성화

1.1.2 Draw Scene

 - 땅과 물을 렌더링할 때 Render to Texture에 렌더링 진행

ID3D11RenderTargetView* renderTargets[1] = { _offscreenRTV.Get()};
_deviceContext->OMSetRenderTargets(1, renderTargets, _depthStencilView.Get());

_deviceContext->ClearRenderTargetView(_offscreenRTV.Get(), 
		reinterpret_cast<const float*>(&Colors::Silver));
_deviceContext->ClearDepthStencilView(_depthStencilView.Get(), 
		D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

   - 이 후 기존 Render Target View를 받아 설정하고 흐리기 알고리즘 적용

renderTargets[0] = _renderTargetView.Get();
_deviceContext->OMSetRenderTargets(1, renderTargets, _depthStencilView.Get());

_blur.BlurInPlace(_deviceContext, _offscreenSRV, _offscreenUAV, 4);

_deviceContext->ClearRenderTargetView(_renderTargetView.Get(), 
        reinterpret_cast<const float*>(&Colors::Silver));
_deviceContext->ClearDepthStencilView(_depthStencilView.Get(), 
        D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

     -  마지막으로 흐려진 Texture를 화면 전체를 덮는 사각형에 입혀 후면 버퍼를 그림

DrawScreenQuad();
HR(_swapChain->Present(0, 0));

1.1.3 Effect File

 - 스레드 그룹은 선분 형태로 구성된 스레드 256개이며, 각 스레드는 이미지의 픽셀 하나를 흐리는 역할 수행

   - 앞에서 말한 흐리기 알고리즘을 구현

     - 각 스레드가 현재 픽셀을 중심으로 한 이웃 픽셀들의 행 행렬의 가중 평균을 구하는 것은 비효율 적임

       - 공유 메모리를 사용하여 비효율성을 극복

[numthreads(N, 1, 1)]
void HorzBlurCS(int3 groupThreadID : SV_GroupThreadID, int3 dispatchThreadID : SV_DispatchThreadID);

 - 공유 메모리를 사용하여 픽셀 N개를 흐리려면 N + 2 * 반지름개의 픽셀을 읽어야 함

   - 이미지 범위 밖의 표본을 이미지 경계로 한정

if (groupThreadID.x < gBlurRadius)
{
    int x = max(dispatchThreadID.x - gBlurRadius, 0);
    gCache[groupThreadID.x] = gInput[int2(x, dispatchThreadID.y)];
}
if (groupThreadID.x >= N - gBlurRadius)
{
    int x = min(dispatchThreadID.x + gBlurRadius, gInput.Length.x - 1);
    gCache[groupThreadID.x + 2 * gBlurRadius] = gInput[int2(x, dispatchThreadID.y)];
}
gCache[groupThreadID.x + gBlurRadius] = gInput[min(dispatchThreadID.xy, gInput.Length.xy - 1)];

 - 모든 스레드가 여기까지의 작업을 완수할 때까지 기다림

GroupMemoryBarrierWithGroupSync();

 - 각 픽셀을 반지름을 통해 개수를 확인하고 흐림

float4 blurColor = float4(0, 0, 0, 0);
[unroll]
for (int i = -gBlurRadius; i <= gBlurRadius; ++i)
{
    int k = groupThreadID.x + gBlurRadius + i;
    blurColor += gWeights[i + gBlurRadius] * gCache[k];
}
gOutput[dispatchThreadID.xy] = blurColor;

 - 나머지 코드는 밑의 글에 있는 함수와 비슷하거나 동일

 

[Direct11] 11. EX App Program - Color Box

1. EX App Program 1.1 Color Box 1.1.1 Geometry Buffer - 색상이 있는 박스를 생성하기 위해 각 정점에 대해 좌표 및 색상 적용 Vertex vertices[] = { { XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4((const float*)&Colors::White) }, { XMFLOAT3

choiprogramming.tistory.com