수업


✅ 주제

  • 3D 렌더링 시, 카메라와의 거리(깊이)에 따라 물체의 전후 관계를 정확하게 판단하고 출력 순서를 자동으로 처리하기 위해 Depth Stencil View 시스템을 구성하고 활용하는 방법을 학습한다.

✅ 개념

  • 지금까지는 Shader 코드 상에서 물체의 Z(깊이) 정보를 별도로 활용하지 않고 그리는 순서에 따라 단순히 화면에 출력하는 방식이었다.
  • 이 경우, 카메라에서 멀리 있는 물체가 앞에 그려지는 비현실적인 결과가 발생할 수 있으며, 이는 렌더링 순서가 출력 결과에 영향을 준다는 것을 의미한다.
  • 이런 문제를 해결하기 위해 GPU가 픽셀마다 Z값(깊이값)을 자동으로 기록하고 비교해 더 앞에 있는 물체만 화면에 남도록 처리하는 방식이 필요하다. 이것이 바로 Depth Stencil View 시스템이다.
  • 추가로, Stencil Buffer는 그림자 마스킹, 실루엣, 스크린 분할 렌더링 등 고급 기술에 사용되며, 이번 강의에서는 아직 직접적으로 사용하지 않지만 구조적으로 함께 포함된다.

✅ 용어 정리

용어설명
Depth Buffer (Z-Buffer)각 픽셀이 화면에 출력되기까지의 깊이 값을 저장하는 버퍼
Stencil Buffer특정 조건에서만 픽셀을 출력하도록 제한하는 마스크용 버퍼
DepthStencilView (DSV)Depth/Stencil Buffer를 Output-Merger 단계에서 사용하는 뷰 객체
DXGI_FORMAT_D24_UNORM_S8_UINT24비트 Depth + 8비트 Stencil 데이터를 저장하는 포맷
OMSetRenderTargetsGPU Output-Merger 단계에 RenderTarget과 DepthStencilView를 동시에 설정
ClearDepthStencilView이전 프레임의 깊이 및 스텐실 값을 초기화하여 새로운 프레임 시작 시 클리어

✅ 코드 분석

📌 1. Graphics 클래스에 DepthStencil 관련 멤버 추가

// Graphics.h 내부
ComPtr<ID3D11Texture2D> _depthStencilTexture;
ComPtr<ID3D11DepthStencilView> _depthStencilView;

void CreateDepthStencilView();
  • _depthStencilTexture: 픽셀마다 깊이 값을 저장할 2D Texture
  • _depthStencilView: 해당 Texture에 접근하기 위한 View 객체

📌 2. Graphics::Init에 DepthStencil 생성 순서 추가

void Graphics::Init(HWND hwnd)
{
    _hwnd = hwnd;

    CreateDeviceAndSwapChain();   // 디바이스, 컨텍스트, 스왑체인 생성
    CreateRenderTargetView();     // 렌더링 결과를 담을 RenderTarget 생성
    CreateDepthStencilView();     // 깊이 정보를 기록할 DepthStencil 생성
    SetViewport();                // 출력 뷰포트 설정
}

📌 3. CreateDepthStencilView 함수 구현

void Graphics::CreateDepthStencilView()
{
    // 1. Depth Texture 생성
    D3D11_TEXTURE2D_DESC desc = {};
    desc.Width = static_cast<uint32>(GAME->GetGameDesc().width);
    desc.Height = static_cast<uint32>(GAME->GetGameDesc().height);
    desc.MipLevels = 1;
    desc.ArraySize = 1;
    desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;   // 깊이: 24bit, 스텐실: 8bit
    desc.SampleDesc.Count = 1;
    desc.Usage = D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;

    HRESULT hr = DEVICE->CreateTexture2D(&desc, nullptr, _depthStencilTexture.GetAddressOf());
    CHECK(hr);

    // 2. DepthStencilView 생성
    D3D11_DEPTH_STENCIL_VIEW_DESC viewDesc = {};
    viewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    viewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
    viewDesc.Texture2D.MipSlice = 0;

    hr = DEVICE->CreateDepthStencilView(_depthStencilTexture.Get(), &viewDesc, _depthStencilView.GetAddressOf());
    CHECK(hr);
}

✔ 핵심 설명

  • DXGI_FORMAT_D24_UNORM_S8_UINT은 깊이값 24비트 + 스텐실 8비트를 지원하는 포맷으로 일반적인 DepthStencil용 포맷이다.
  • CreateTexture2D는 실제 깊이값을 담을 메모리를 생성하는 함수이고,
  • CreateDepthStencilView는 이 Texture를 DepthStencil 용도로 GPU에 넘겨주는 View 객체를 만드는 함수이다.

📌 4. RenderBegin에서 OMSetRenderTargets 수정

void Graphics::RenderBegin()
{
    _deviceContext->OMSetRenderTargets(1, _renderTargetView.GetAddressOf(), _depthStencilView.Get());
    _deviceContext->ClearRenderTargetView(_renderTargetView.Get(), (float*)(&GAME->GetGameDesc().clearColor));
  • 이 코드로 출력 대상(RenderTarget)과 깊이 출력 대상(DepthStencilView)을 동시에 바인딩해준다.
  • 이제 GPU는 그려지는 픽셀마다 깊이 값을 기록하고 비교할 수 있게 된다.

📌 5. RenderBegin에서 ClearDepthStencilView로 초기화 추가

_deviceContext->ClearDepthStencilView(
    _depthStencilView.Get(),
    D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL,  // 깊이와 스텐실 모두 초기화
    1.0f, // 초기 깊이값: 가장 먼 거리
    0     // 초기 스텐실값: 보통은 0
);

✔ 주석 설명

  • 이 초기화 코드를 호출하지 않으면 이전 프레임의 깊이 값이 그대로 남아 현재 프레임에 영향을 준다.
  • 따라서 매 프레임마다 깊이 값을 1로(화면 뒤쪽으로) 초기화해야 제대로 렌더링된다.

✅ 핵심

  1. DepthStencilView는 각 픽셀의 깊이 값을 저장하여 GPU가 전후 관계를 판단할 수 있도록 하는 핵심 시스템이다.
  2. 단순히 그리는 순서에 따라 출력하던 기존 방식과 달리, Z값을 기준으로 더 가까운 픽셀만 출력되도록 자동 처리된다.
  3. 이를 위해 Texture2D와 View 객체를 생성하고, OMSetRenderTargets로 Output-Merger에 세팅해야 한다.
  4. 그리고 ClearDepthStencilView로 매 프레임마다 깊이 초기화 작업을 반드시 수행해야 한다.
  5. Stencil 기능은 현재 활용되지 않지만, 그림자/실루엣/스크린 마스킹 등 고급 기법의 기반이 되므로 구조에 함께 포함시킨다.
  6. 이 시스템이 구현되면, 더 이상 그리는 순서에 의존하지 않고 깊이에 따른 정확한 3D 표현이 가능해진다.

profile
李家네_공부방

0개의 댓글