이 섹션에서는 출력-병합 단계에 대한 깊이 스텐실 버퍼 및 깊이 스텐실 상태를 설정하는 단계를 설명합니다.
깊이 스텐실 버퍼 및 해당 깊이 스텐실 상태를 사용하는 방법을 알고 나면 고급 스텐실 기술을 참조하세요.
Depth-Stencil 리소스 만들기
텍스처 리소스를 사용하여 깊이 스텐실 버퍼를 만듭니다.
ID3D11Texture2D* pDepthStencil = NULL;
D3D11_TEXTURE2D_DESC descDepth;
descDepth.Width = backBufferSurfaceDesc.Width;
descDepth.Height = backBufferSurfaceDesc.Height;
descDepth.MipLevels = 1;
descDepth.ArraySize = 1;
descDepth.Format = pDeviceSettings->d3d11.AutoDepthStencilFormat;
descDepth.SampleDesc.Count = 1;
descDepth.SampleDesc.Quality = 0;
descDepth.Usage = D3D11_USAGE_DEFAULT;
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
descDepth.CPUAccessFlags = 0;
descDepth.MiscFlags = 0;
hr = pd3dDevice->CreateTexture2D( &descDepth, NULL, &pDepthStencil );
Depth-Stencil 상태 만들기
깊이 스텐실 상태는 출력-병합 단계에 깊이 스텐실 테스트수행하는 방법을 알려줍니다. 깊이 스텐실 테스트는 지정된 픽셀을 그려야 하는지 여부를 결정합니다.
D3D11_DEPTH_STENCIL_DESC dsDesc;
// Depth test parameters
dsDesc.DepthEnable = true;
dsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsDesc.DepthFunc = D3D11_COMPARISON_LESS;
// Stencil test parameters
dsDesc.StencilEnable = true;
dsDesc.StencilReadMask = 0xFF;
dsDesc.StencilWriteMask = 0xFF;
// Stencil operations if pixel is front-facing
dsDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
dsDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Stencil operations if pixel is back-facing
dsDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
dsDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
dsDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Create depth stencil state
ID3D11DepthStencilState * pDSState;
pd3dDevice->CreateDepthStencilState(&dsDesc, &pDSState);
DepthEnable 및 StencilEnable은 깊이 및 스텐실 테스트를 활성화(및 사용하지 않도록 설정)합니다. 깊이 테스트를 비활성화하고 깊이 버퍼에 쓰지 않도록 하려면 DepthEnable을 false로 설정하십시오. 스텐실 테스트를 비활성화하고 스텐실 버퍼에 쓰지 않도록 StencilEnable을 FALSE로 설정합니다(DepthEnable이 FALSE이고 StencilEnable이 TRUE인 경우 깊이 테스트는 스텐실 연산에서 항상 통과됩니다.)
DepthEnable은 출력-병합 단계에만 영향을 줍니다. 데이터가 픽셀 셰이더에 입력되기 전에 값의 클리핑, 깊이 바이어스 또는 클램핑에는 영향을 주지 않습니다.
Depth-Stencil 데이터를 OM 스테이지에 바인딩
깊이 스텐실 상태를 바인딩합니다.
// Bind depth stencil state
pDevice->OMSetDepthStencilState(pDSState, 1);
뷰를 사용하여 깊이 스텐실 리소스를 바인딩합니다.
D3D11_DEPTH_STENCIL_VIEW_DESC descDSV;
descDSV.Format = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
descDSV.Texture2D.MipSlice = 0;
// Create the depth stencil view
ID3D11DepthStencilView* pDSV;
hr = pd3dDevice->CreateDepthStencilView( pDepthStencil, // Depth stencil texture
&descDSV, // Depth stencil desc
&pDSV ); // [out] Depth stencil view
// Bind the depth stencil view
pd3dDeviceContext->OMSetRenderTargets( 1, // One rendertarget view
&pRTV, // Render target view, created earlier
pDSV ); // Depth stencil view for the render target
렌더링 대상 뷰의 배열은 ID3D11DeviceContext::OMSetRenderTargets전달될 수 있으나, 모든 렌더링 대상 뷰는 단일 깊이 스텐실 뷰에 해당합니다. Direct3D 11의 렌더링 대상 배열은 애플리케이션이 기본 수준에서 동시에 여러 렌더링 대상에 렌더링할 수 있도록 하는 기능입니다. 렌더링 대상 배열은 ID3D11DeviceContext::OMSetRenderTargets(기본적으로 Direct3D 9에서 사용하는 방법)에 대한 여러 호출을 통해 렌더링 대상을 개별적으로 설정하는 데 비해 향상된 성능을 제공합니다.
렌더링 대상은 모두 동일한 유형의 리소스여야 합니다. 다중 샘플 앤티앨리어싱을 사용하는 경우 모든 바인딩된 렌더링 대상 및 깊이 버퍼에는 동일한 샘플 수가 있어야 합니다.
버퍼를 렌더링 대상으로 사용하는 경우 깊이-스텐실 테스트 및 여러 개의 렌더링 대상이 지원되지 않습니다.
- 8개의 렌더링 대상을 동시에 바인딩할 수 있습니다.
- 모든 렌더링 대상은 모든 차원의 크기가 동일해야 합니다(너비와 높이, 3D의 경우 깊이 또는 *배열 형식의 경우 배열 크기).
- 각 렌더링 대상에는 다른 데이터 형식이 있을 수 있습니다.
- 쓰기 마스크는 렌더링 대상에 기록되는 데이터를 제어합니다. 출력 쓰기 마스크는 렌더링 대상마다, 또한 구성 요소에 따라 데이터가 렌더링 대상에 기록되는 방식을 제어합니다.
고급 스텐실 기술
깊이 스텐실 버퍼의 스텐실 부분은 합성, 데칼, 외곽선 그리기와 같은 렌더링 효과를 만드는 데 사용할 수 있습니다.
합성
애플리케이션은 스텐실 버퍼를 사용하여 2D 또는 3D 이미지를 3D 장면에 합성할 수 있습니다. 스텐실 버퍼의 마스크는 렌더링 타깃 표면의 특정 영역을 가리는 데 사용됩니다. 텍스트나 비트맵과 같은 저장된 2D 정보를 가려진 영역에 쓸 수 있습니다. 또는 애플리케이션이 렌더링 대상 표면의 스텐실 마스크 영역에 추가 3D 기본 형식을 렌더링할 수 있습니다. 전체 장면을 렌더링할 수도 있습니다.
게임은 종종 여러 3D 장면을 함께 합성합니다. 예를 들어, 주행 게임은 일반적으로 백미러를 표시합니다. 거울은 운전자 뒤에 있는 3D 장면을 보여줍니다. 기본적으로 드라이버의 전방 보기와 함께 합성된 두 번째 3D 장면입니다.
데칼 작업
Direct3D 애플리케이션은 데칼링을 사용하여 렌더링 대상 화면에 그려지는 특정 기본 이미지의 픽셀을 제어합니다. 애플리케이션은 원형 이미지에 데칼을 적용하여 동면 다각형이 올바르게 렌더링되도록 합니다.
예를 들어 도로에 타이어 표시와 노란색 선을 적용할 때 표시가 도로 바로 위에 표시되어야 합니다. 그러나 표시와 도로의 z 값은 동일합니다. 따라서 깊이 버퍼는 둘 사이의 깨끗한 분리를 생성하지 않을 수 있습니다. 후면 기본 형식의 일부 픽셀은 전면 기본 형식 위에 렌더링될 수 있으며 그 반대의 경우도 마찬가지입니다. 결과 이미지는 프레임에서 프레임으로 반짝이는 것처럼 보입니다. 이 효과를 z-fighting 또는 깜박임이라고 합니다.
이 문제를 해결하려면 스텐실을 사용하여 데칼이 부착될 뒷면 원시 도형의 부분을 마스킹합니다. z 버퍼링을 해제하고 전면 기본 형식의 이미지를 렌더링 대상 표면의 마스킹된 영역으로 렌더링합니다.
이 문제를 해결하기 위해 여러 텍스처 혼합을 사용할 수 있습니다.
윤곽선 및 실루엣
스텐실 버퍼를 사용하여 개요 및 실루엣과 같은 추상 효과를 더 많이 적용할 수 있습니다.
애플리케이션이 스텐실 마스크를 생성하는 것과 스텐실 마스크를 이미지에 적용하는 두 번째 렌더링 패스 중 하나이지만 두 번째 패스에서 기본 형식이 약간 더 작은 경우 결과 이미지에는 기본 형식의 윤곽선만 포함됩니다. 그런 다음 애플리케이션은 이미지의 스텐실 마스크 영역을 프리미티브에 엠보싱된 효과를 주기 위해 단색으로 채울 수 있습니다.
스텐실 마스크가 렌더링하는 기본 형식과 크기 및 모양이 같으면 결과 이미지에는 기본 형식이 있어야 하는 구멍이 포함됩니다. 그런 다음 응용 프로그램은 원형의 실루엣을 생성하기 위해 검은 색으로 구멍을 채울 수 있습니다.
Two-Sided 스텐실
섀도 볼륨은 스텐실 버퍼를 사용하여 그림자를 그리는 데 사용됩니다. 애플리케이션은 기하 도형을 폐색하고 실루엣 가장자리를 계산하고 조명에서 3D 볼륨 세트로 압출하여 캐스팅된 섀도 볼륨을 계산합니다. 그런 다음 이러한 볼륨은 스텐실 버퍼에 두 번 렌더링됩니다.
첫 번째 렌더링은 전면을 향하는 폴리곤을 그리며, 스텐실 버퍼 값을 증가시킵니다. 두 번째 렌더링은 그림자 볼륨의 후면 다각형을 그리고 스텐실 버퍼 값을 감소합니다. 일반적으로 증가된 값과 감소된 모든 값은 서로를 취소합니다. 그러나 이 장면은 이미 일반 기하 도형으로 렌더링되어 일부 픽셀이 섀도 볼륨이 렌더링될 때 z 버퍼 테스트에 실패했습니다. 스텐실 버퍼에 남아 있는 값은 그림자에 있는 픽셀에 해당합니다. 잔여 스텐실 버퍼 콘텐츠는 마스크로 사용되어 대형 검은색 쿼드를 알파 블렌딩하여 장면에 삽입합니다. 스텐실 버퍼가 마스크로 작동하면 그림자에 있는 픽셀이 어둡게 됩니다.
즉, 그림자 기하 도형은 광원당 두 번 그려지므로 GPU의 꼭짓점 처리량에 압력을 가합니다. 양면 스텐실 기능은 이러한 상황을 완화하도록 설계되었습니다. 이 방법에서는 두 개의 스텐실 상태 집합(아래 명명됨)이 있으며, 하나는 앞면 삼각형에 대해 각각 설정되고 다른 하나는 후면 삼각형에 대해 설정됩니다. 이렇게 하면 빛당 그림자 볼륨당 하나의 패스만 그려집니다.
2면 스텐실 구현의 예는 ShadowVolume10 샘플에서 찾을 수 있습니다.
Depth-Stencil 버퍼를 텍스처로 읽기
깊이 스텐실 버퍼가 비활성 상태일 때도 셰이더에서 텍스처로 읽을 수 있습니다. 깊이-스텐실 버퍼를 텍스처로 읽는 애플리케이션은 두 번에 걸쳐 렌더링되며, 첫 번째 단계에서는 깊이-스텐실 버퍼에 쓰고, 두 번째 단계에서는 버퍼에서 읽습니다. 이렇게 하면 셰이더가 버퍼에 이전에 기록된 깊이 또는 스텐실 값을 현재 렌더링 중인 픽셀의 값과 비교할 수 있습니다. 비교 결과를 사용하여 파티클 시스템에서 그림자 매핑 또는 부드러운 입자와 같은 효과를 만들 수 있습니다.
깊이 스텐실 리소스와 셰이더 리소스 모두로 사용할 수 있는 깊이 스텐실 버퍼를 만들려면 Depth-Stencil 리소스 만들기 섹션에서 코드 샘플을 몇 가지 변경해야 합니다.
깊이 스텐실 리소스에는 DXGI_FORMAT_R32_TYPELESS 같은 형식이 없어야 합니다.
descDepth.Format = DXGI_FORMAT_R32_TYPELESS;
깊이 스텐실 리소스는 D3D10_BIND_DEPTH_STENCIL 및 D3D10_BIND_SHADER_RESOURCE 바인딩 플래그를 모두 사용해야 합니다.
descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL | D3D10_BIND_SHADER_RESOURCE;
또한 깊이 버퍼에 대한 셰이더 리소스 뷰를 D3D11_SHADER_RESOURCE_VIEW_DESC 구조를 사용하여 생성해야 하며, 이를 위해 ID3D11Device::CreateShaderResourceView를 사용합니다. 셰이더 리소스 뷰는 깊이 스텐실 리소스를 만들 때 지정된 형식이 없는 형식과 동일한 DXGI_FORMAT_R32_FLOAT 같은 형식화된 형식을 사용합니다.
첫 번째 렌더링 패스에서 깊이 버퍼는 바인딩 Depth-Stencil 데이터에 설명된 대로 OM 스테이지 섹션에 바인딩됩니다. D3D11_DEPTH_STENCIL_VIEW_DESC에 전달되는 형식은 DXGI_FORMAT_D32_FLOAT과 같은 형식화된 형식을 사용할 것입니다. 첫 번째 렌더링이 통과한 후 깊이 버퍼에는 장면의 깊이 값이 포함됩니다.
두 번째 렌더링에서는 ID3D11DeviceContext::OMSetRenderTargets 함수를 사용하여 깊이 스텐실 보기를 NULL 또는 다른 깊이 스텐실 리소스로 설정하고 셰이더 리소스 뷰는 ID3D11EffectShaderResourceVariable::SetResource사용하여 셰이더에 전달됩니다. 이렇게 하면 셰이더가 첫 번째 렌더링 패스에서 계산된 깊이 값을 조회할 수 있습니다. 첫 번째 렌더링 패스의 관점이 두 번째 렌더링 패스와 다른 경우 깊이 값을 검색하려면 변환을 적용해야 합니다. 예를 들어 그림자 매핑 기술을 사용하는 경우 첫 번째 렌더링 패스는 광원의 관점에서 이루어지고 두 번째 렌더링 패스는 뷰어의 관점에서 전달됩니다.
관련 항목