1. 스텐실 버퍼 Stencil Buffer
🔸 특징
- 스텐실 버퍼는 후면 버퍼 및 깊이 버퍼와 해상도가 같다.
- 스텐실 버퍼를 지정하면 그 스텐실 버퍼는 깊이 버퍼에 부착된다.
- 픽셀 단편들이 후면 버퍼에 기록되지 못하게 하는 역할을 한다.
- CD3DX12_DEPTH_STENCIL_DESC구조체 채우고, D3D12_GRAPHICS_PIPELINE_STATE_DESC 설정한다.
2. 스텐실 판정
스텐실 버퍼를 이용하면 장면이 후면 버퍼의 특정 영역에만 렌더링되지 않게 만들수 있다. 스텐실을 적용하는 경우, 주어진 한 픽셀이 후면 버퍼에 기록되는지 아닌지는 스텐실 판정의 결과에 따라 결정된다. 스텐실 판정은 픽셀이 래스터화되는 과정에서, 즉 출력 병합기 단계에서 일어난다.
- 픽셀을 허용 : 후면 버퍼에 그리겠다.
- 픽셀을 기각 : 후면 버퍼에서 자르겠다.
- value : 스텐실 버퍼에 이미 있던 픽셀의 값
- stencilRef: 응용 프로그램이 지정한 스탠실 기준값
- stencilReadMask : 좌변 우변 같은 값으로 마스킹값
3. 거울 그리기 PSO (pipeline_state_object)중요코드
1) 파이프라인 설정에서 스탠실 상태 만들어주기.
- 거울 픽셀들을 스텐실 버퍼에 기록하기 위해 거울을 렌더링할때 쓰는 pso
mirrorBlendState.RenderTarget[0].RenderTargetWriteMask = 0;
색상 성분들이 후면 버퍼에 기록되지 않는다.
mirrorDSS.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
깊이 버퍼 쓰기가 비활성화 된다.
mirrorDSS.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
거울을 스텐실 버퍼에 렌더링할 때에는 스텐실 판정이 항상 성공(통과)하도록 비교함수를 alway로 설정한다.
mirrorDSS.FrontFace.StencilPassOp = D3D12_STENCIL_OP_REPLACE;
판정 성공시 기존 스텐실 항목이 항상 1로 대체되도록 StencilRef를 1로, 비교연산자를 D3D12_STENCIL_OP_REPLACE로 지정한다.
mirrorDSS.BackFace.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
깊이 판정이 실패해도 스텐실 버퍼는 변하지 않는다.
- 반사된 오브젝트를 거울의 가시적 부분에만 그릴 때 사용.
reflectionsDSS.BackFace.StencilFunc = D3D12_COMPARISON_FUNC_EQUAL;
스텐실 버퍼 항목이 1인 경우에만 판정이 성공하게 설정한다. 이를 위해 stencilref를 1로 설정하고 비교연산자는 D3D12_COMPARISON_FUNC_EQUAL로 설정한다.
drawReflectionsPsoDesc.PS =
{
reinterpret_cast<BYTE*>(mShaders["alphaTestedPS"]->GetBufferPointer()),
mShaders["alphaTestedPS"]->GetBufferSize()
};
책과 다르게 알파 clip이 이뤄진 상자를 반사시키기 때문에 alphaTestps를 넣어줘서 반사된 물체도 알파처리 될수 있게 해주었다.
4. 거울 그리기 Draw 중요코드
auto passCB = mCurrFrameResource->PassCB->Resource();
다음 상수 버퍼로 넘어 갈 수있도록 상수버퍼 사이즈를 알아둔다.
mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
// 불투명한 항목 (바닥, 벽, 상자등을 그린다.)
DrawRenderItems(mCommandList.Get(), mRenderItems[(int)RenderLayer::Opaque]);
원래 기본 상수버퍼로 그림을 그린다. 바닥, 벽, 상자, 기둥등등
mCommandList->OMSetStencilRef(1);
mCommandList->SetPipelineState(mPSOs["markStencilMirrors"].Get());
DrawRenderItems(mCommandList.Get(), mRenderItems[(int)RenderLayer::Mirrors]);
mRenderItems[(int)RenderLayer::Mirrors] 이 아이템 안에는 거울만 있다. OMSetStencilRef 설정으로 판정 성공시 1이 기록된다.
mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress() + 1 * passCBByteSize);
mCommandList->SetPipelineState(mPSOs["drawStencilReflections"].Get());
DrawRenderItems(mCommandList.Get(), mRenderItems[(int)RenderLayer::Reflected]);
반사된 조명으로 넘어가기 위해 상수 버퍼를 바꿔주 반사된 오브젝트를 거울의 가시적 부분에만 그릴 때 사용하는 상태객체로 변경후 반사된 물체를 그린다.
'🎯 game engine > ◽ directX12' 카테고리의 다른 글
[DirectX12] 섀도우 매핑 (shadow mapping), 섀도우 알고리즘 상세 정리 (0) | 2024.12.18 |
---|---|
[DirectX12] 큐브맵 만들기 / StructuredBuffer (0) | 2024.11.26 |
[DirectX12] 조명의 종류 (0) | 2023.12.19 |
[DirectX12] 조명 연산을 위한 법선 벡터, 법선 벡터의 변환 (0) | 2023.12.14 |
[DirectX12] 원기둥의 정점 찍기/렌더링 과정 이해하기 (1) | 2023.12.12 |
안 하는 것 보다 낫겠지
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!