Mirror and Reflection (DepthStencil Test)

Date:     Updated:

카테고리:

태그:

홍정모님의 그래픽스 새싹코스 강의를 듣고 정리한 내용입니다.


🐥 Mirror and Reflection

1

거울에 비치는 물체를 표현하기 위한 방법 중 가장 먼저 떠오르는 것은 Ray Tracing을 이용한 방법일 것이다. 하지만 Rasterization을 이용하는 전통적인 렌더링 파이프라인에서는 ray tracing을 사용하지 않는다. 월드에 존재하는 오브젝트들을 통쨰로 거울 뒤의 세상으로 반사시킨 뒤, Stencil Test를 이용해 거울 속 세상을 별도로 렌더링 한다.


Stencil Buffer

stencil_buffer

Stencil Buffer의 대표적인 활용법 중 하나는 Rasterize 이후 0/1 값으로 렌더링 할 부분을 표기해주는 버퍼이다. 거울 평면의 경우 거울 속 전체 월드를 그리는 것은 아주 큰 낭비이다. 이럴 경우 Stencil Buffer를 이용해여 거울의 크기만큼만 렌더링을 해주면 된다.


🐥 DepthStencil State

Stencil Buffer를 이용한 거울을 구현할 경우 여러가지의 DepthStencil State가 필요하다.

  • 기존 World를 렌더링하기 위한 DSS (Default State)
  • Stencil Buffer에 거울 영역을 표기해주기 위한 DSS
  • Stencil Test를 통과한 오브젝트들 렌더링하기 위한 DSS


Default State

// DepthStencilView 생성

D3D11_TEXTURE2D_DESC desc;

// ...

desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
ThrowIfFailed(m_device->CreateTexture2D(
    &desc, 0, m_depthStencilBuffer.GetAddressOf()));
ThrowIfFailed(m_device->CreateDepthStencilView(
    m_depthStencilBuffer.Get(), NULL, m_depthStencilView.GetAddressOf()));

  • BindFlags : D3D11_BIND_DEPTH_STENCIL
  • Format : DXGI_FORMAT_D24_UNORM_S8_UINT
    • 보통 버퍼들은 픽셀 당 32bit 데이터 들고 있음
    • 메모리를 효율적으로 사용하기 위해 (depth 24bit + stencil 8bit)를 함께 들고다님


// default DSS
D3D11_DEPTH_STENCIL_DESC dsDesc;
ZeroMemory(&dsDesc, sizeof(dsDesc));
dsDesc.DepthEnable = true;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; // 쓰기 킬지 말지
dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
dsDesc.StencilEnable = false; // Stencil 불필요
dsDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
dsDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
  • DepthWriteMask :
    • D3D11_DEPTH_WRITE_MASK_ZERO : DepthStencil Buffer 쓰기 끄기
    • D3D11_DEPTH_WRITE_MASK_ALL : DepthStencil Buffer 쓰기 켜기
  • DepthFunc : D3D11_COMPARISON_LESS (작을 경우 통과)
  • StencilReadMask : D3D11_DEFAULT_STENCIL_READ_MASK;
  • StencilWriteMask : D3D11_DEFAULT_STENCIL_WRITE_MASK;
// 앞면에 대해서 어떻게 작동할지 설정
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

// 뒷면에 대해 어떻게 작동할지 설정 (뒷면도 그릴 경우)
dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

ThrowIfFailed(
        m_device->CreateDepthStencilState(&dsDesc,  m_drawDSS.GetAddressOf()));
  • StencilPassOp : depth, stencil 둘 다 pass일 경우
  • StencilDepthFailOp : depth fail, stencil pass일 경우
  • StencilFailOp : depth,stencil 둘 다 fail일 경우


Stencil Test 통과한 픽셀만 처리

dsDesc.DepthEnable = true;   
dsDesc.StencilEnable = true; // Stencil 사용
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; 
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_EQUAL; 

ThrowIfFailed(m_device->CreateDepthStencilState(
    &dsDesc, m_drawMaskedDSS.GetAddressOf()));
  • StencilFunc = D3D11_COMPARISON_EQUAL;
    • OMSetDepthStecilState(.., 1) 에서 설정한 값 1과 같을 경우에만 stencil test 통과하도록 설정
  • 참고로 거울 속 세상을 그릴 때에는 Rasterizer State의 Clockwise를 바꿔줘야 함(반사시키면서 ccw로 변형)

Blending

D3D11_BLEND_DESC mirrorBlendDesc;

// ...

mirrorBlendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_BLEND_FACTOR;
mirrorBlendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_BLEND_FACTOR;
mirrorBlendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;

ThrowIfFailed(m_device->CreateBlendState(&mirrorBlendDesc,
                                          m_mirrorBS.GetAddressOf()));
  • OMSetBlendState(…, blendColor, …)
    • 이때 넘어온 color값들이 Blend Factor
  • (Source color * blend factor) + (Destination color * (1 - blend factor))
    • source는 거울 자체의 color
    • destination은 반사된 물체의 color


🐥 Results

ezgif com-crop



맨 위로 이동하기

Graphics 카테고리 내 다른 글 보러가기

댓글 남기기