※ 아래의 내용들은 DirectX 11을 이용한 3D 게임 프로그래밍 입문 책의 내용을 바탕으로 작성된 것입니다.
3. 해골 예제에서 벽 뒤로 반사상이 보이도록 만들어보라.(그림 10.1의 왼쪽처럼)
- 예제를 구현하는 순서는 아래와 같다.
1. 바닥과 벽 등을 보통의 방법으로 렌더링 한다. 거울은 아직 그리지 않는다.
2. 스텐실 버퍼를 0으로 지운다.
3. 거울을 스텐실 버퍼에만 렌더링한다.
4. 반사된 두개골을 후면 버퍼와 스텐실 버퍼에 렌더링한다.
5. 거울 자체를 후면 버퍼에 통상적인 방식으로 렌더링하되, 반사된 물체가 가려지지 않도록 하기 위해 투명도 혼합을 적용한다.
위의 과정 중 4번째 단계에서, 반사된 두개골 기하구조의 픽셀들은 스텐실 판정을 통과한 경우에만 후면 버퍼에 기록되도록 하고있다.
해당 과정만 생략하게 되면 벽 뒤로 반사상이 보이도록 만들 수 있다.
4. 해골 예제의 그림자 이중 혼합 문제가 발생하도록 예제를 수정하라.(그림 10.10의 왼쪽처럼)
- 그림의 이중 혼합과 관련된 내용은 책 10.5.4절(442p)에 나와있다.
- 이중 혼합 문제를 스텐실 버퍼를 이용해 해결하였으므로, 해당 부분의 코드만 찾아서 위의 3번 문제와 마찬가지로 주석처리하면 해결할 수 있다.
※ 실질적인 문제 해결을 위한 스텐실 버퍼 설정은 530행의 코드이며, 536행은 설정했던 깊이ㆍ스텐실 설정을 다시 초기화 해주는 코드이다. 530행을 주석처리 하면서 깊이ㆍ스텐실 버퍼를 별도로 수정하지 않은 것이 되므로 536행 또한 함께 주석처리 하였다.
5. 기존에 주어진 깊이ㆍ스텐실 설정을 문제에서 주어진 설정으로 변경하여 적용하라.
- 문제에서 주어진 깊이ㆍ스텐실 설정을 적용하기 위해 RenderStates.cpp 파일에 위와 같은 코드를 추가하였다.
=> NonDepthForWallDSS 등의 변수는 RenderStates.h 파일에서 추가해야 한다.
- 모든 설정에서 스텐실 버퍼를 사용하지 않고, 위에서부터 순서대로 벽의 깊이 판정 비활성화, 해골의 깊이 판정 활성화, 벽의 깊이 판정 활성화 로 설정하는 코드이다.
- OMSetDepthStencilState() 함수를 이용해서 위에서 설정한 깊이ㆍ스텐실 버퍼 설정을 적용할 수 있다.
=> RenderStates::NonDepthForWallDSS 로 설정하면 벽의 깊이 판정을 비활성화 한다.
=> RenderStates::OnlyDepthForWallDSS 로 설정하면 벽의 깊이 판정을 활성화 한다.
- 기존의 스텐실 버퍼를 활용하던 코드에서 깊이 판정만 활성화 하고 스텐실 버퍼는 사용하지 않는 상태로 변경하였다.
- 벽의 깊이 판정을 비활성화, 반사상의 해골의 깊이 판정을 활성화 함으로써 반사상의 해골이 먼저 그려져있던 원본의 해골보다는 뒤에 그려지지만 깊이 판정이 비활성화 된 벽 보다는 앞에서 그려지고 있다.
=> 반사상의 해골이 가장 마지막에 그려졌기 때문에, 깊이 판정을 하지 않으면 가장 마지막에 그려진 그림이 가장 앞에 있는 것처럼 보이게 된다.
=> 여기서 벽의 깊이 판정만 비활성화 되어 있기 때문에 반사상의 해골이 벽 보다는 앞에 그려진 것처럼 보이는 것이다.
- 벽의 깊이 판정을 활성화하면, 모든 깊이 판정이 정상적으로 동작하기 때문에 벽 뒤의 반사상 해골이 의도대로 그려지게 된다.
6. 거울 반사상을 렌더링할 때 삼각형 감기 순서를 통상적인 관례의 반대로 설정하지 않도록 예제를 수정하라.
- 물체가 거울에 반사될 때, 오른쪽 그림과 같이 물체가 뒤집히게 된다. 따라서 반사상의 경우엔 삼각형 감기 순서를 통상적인 관례의 반대로 해주어야 한다.
7. 9장 혼합 예제에 원기둥을 하나 그린 후, 제공되는 60 프레임짜리 번개 애니메이션을 가산 혼합을 이용해서 원기둥에 텍스처로 입혀라.
- 문제를 3단계에 나눠 해결한다.
1. 원기둥 그리기
2. 원기둥에 60프레임짜리 번개 애니메이션 적용
3. 적용된 텍스처 가산 혼합하기.
- 원기둥 그리기는 6장에서 공부했던 GeometryGenerator 클래스를 이용하면 쉽게 해결 가능.
=> 헷갈리는 부분은 9장 혼합 예제에서 큐브를 그리는 코드가 있으니 해당 부분을 참고.
- 원기둥에 60프레임짜리 번개 애니메이션 적용은 8장 텍스처 적용 연습문제에서 했던 방법을 그대로 이용하면 됨.
=> 제공되는 이미지 파일이 bmp여서 dds 파일로 변경 후 작업했습니다.
- 적용된 텍스처 가산 혼합하기.
=> 우선 RenderStates 클래스에서 가산 혼합을 위한 BlendState, 가산 혼합 과정에서 깊이 쓰기를 비활성화 하기 위한 DepthStencilState를 각각 정의합니다.
=> 원기둥을 그리는 과정에서 위에서 설정한 States들을 모두 설정합니다.
=> 깊이 쓰기를 비활성화 하기 때문에, 원기둥을 최대한 늦게 그려야 다른 물체에 가려지지 않습니다.
==> 물은 투명도 혼합을 이용하기 때문에 원기둥을 물보다는 먼저 그려야 합니다.
==> 기존 예제에서는 지형과 물을 그리는 부분을 for문 하나로 해결하는데, 저는 지형을 그린 후 원기둥을 그리고나서 물을 그리도록 하기 위해 해당 부분을 나눴습니다.
※ 원기둥이 나중에 그려진 물체들에 가려지지 않도록 하는 다른 방법이 있는지 모르겠습니다. 저는 여기서 최대한 원기둥을 나중에 그리는 방식으로 해결하였습니다.( 깊이 쓰기가 비활성화 된 것이지 깊이 판정 및 깊이 읽기는 여전히 활성화 되어 있기 때문에 이런 방법으로 해결이 가능합니다. )
8. 9장의 혼합 예제에 쓰인 장면의 깊이 복잡도를 렌더링하라. 단, 스텐실 버퍼를 활용하는 방법으로 해결하라.
- 깊이 복잡도를 측정하기 위해 스텐실 버퍼를 계수기(counter)로 활용한 방법이다.
1. 렌더링 시작 시 스텐실 버퍼를 0으로 지운다.
2. 장면을 스텐실 버퍼에만 렌더링 하되, 각 픽셀 단편이 처리될 때마다 해당 스텐실 버퍼 항목이 1씩 증가되게 한다.
3. 각 깊이 복잡도 수준 k마다 하나의 색상 C(k)를 지정한다.
4. 투영 창 전체를 덮는 사각형 하나를 C(k) 색으로 그린다. 스텐실 비교 함수와 기준 값을 이용하면, 깊이 복잡도가 k인 픽셀들은 C(k) 색상이 된다.
- 스텐실 버퍼를 0으로 지우는 것은 기존의 코드에도 있던 내용임.
=> md3dImmediateContext->ClearDepthStencilView(mDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
- 장면을 스텐실 버퍼에만 렌더링 하되, 각 픽셀 단편이 처리될 때마다 해당 스텐실 버퍼 항목 1씩 증가
=> 후면 버퍼에 그림이 그려지지 않도록 혼합 상태를 설정해준다.
==> noRenderTargetWritesDesc.RenderTarget[0].RenderTargetWriteMask = 0;
=> 픽셀 단편이 처리될 때마다 해당 스텐실 버퍼 항목을 증가시키려면 Depth/Stencil 상태를 설정해준다. (책에 해당 내용은 자세히 설명되어 있음. 446p)
- 각 깊이 복잡도 수준 k마다 하나의 색상 C(k)를 지정한다.
=> 투영 창 전체를 덮는 사각형에 적용할 색상 재질 5가지를 만든다.
※ 본인은 깊이 복잡도 수준을 1, 2, 3, 4, 5 총 5단계로 나누었기 때문에 색상 재질도 5가지만 만들었지만, 필요한 사람은 더 적게 만들거나 더 많이 만들어도 상관없음.
- 스텐실 비교 함수와 기준 값을 이용하면, 깊이 복잡도가 k인 픽셀들은 C(k) 색상이 된다.
=> 스텐실 비교 함수와 기준 값은 10장의 거울 예제를 생각하면 된다.
=> md3dImmediateContext->OMSetDepthStencilState(RenderStates::DepthLevelDrawDSS, 1);
==> 위의 코드는 스텐실 값이 1인 픽셀들을 찾는 함수이다. (Depth/Stencil 상태를 해당 내용으로 미리 설정해뒀다는 가정 하에)
9. 9장의 혼합 예제에 쓰인 장면의 깊이 복잡도를 렌더링하라. 단, 가산 혼합을 이용하는 방법으로 해결하라.
- 가산 혼합을 이용하는 방식이란, 후면 버퍼를 모두 지운 후 깊이 버퍼를 비활성화 하고 장면을 가산혼합해서 그리는 것이다.
=> 원본 혼합 계수와 대상 혼합 계수를 모두 D3D11_BLEND_ONE으로 설정하고 가산 혼합한다.
=> 장면의 모든 물체를 (0.05f, 0.05f, 0.05f) 같이 명도가 낮은 색으로 렌더링 한다.
10. 깊이 판정을 통과한 픽셀들의 개수를 세는 방법을 설명하라. 깊이 판정에 실패한 픽셀들의 개수를 세는 방법을 설명하라.
- 두 가지 경우 모두 스텐실 버퍼를 이용하면 해결할 수 있다.
1. 깊이 판정을 통과한 픽셀들
D3D11_DEPTH_STENCIL_DESC 구조체 멤버 중 FrontFace, BackFace의 StencilPassOp 항목은 픽셀 단편이 스텐실 판정, 깊이 판정 모두 통과했을 때 스텐실 버퍼 갱신 방식을 결정하는 항목이다. 스텐실 판정을 항상 통과하도록 ALWAYS로 설정해둔다면 깊이 판정을 통과한 픽셀들은 자동으로 해당 항목에 의해 스텐실 버퍼에 특정 방식으로 갱신될 것이다.
2. 깊이 판정에 실패한 픽셀들
D3D11_DEPTH_STENCIL_DESC 구조체 멤버 중 FrontFace, BackFace의 StencilDepthFailOp 항목은 픽셀 단편이 스텐실 판정에 통과했으나 깊이 판정에 실패했을 때 스텐실 버퍼 갱신 방식을 결정하는 항목이다. 마찬가지로 스텐실 판정을 항상 통과하도록 ALWAYS로 설정해둔다면 깊이 판정을 실패한 픽셀들은 자동으로 해당 항목에 의해 스텐실 버퍼에 특정 방식으로 갱신될 것이다.
11. 두개골뿐만 아니라 장면의 바닥도 거울에 반사되도록 거울 예제를 수정하라.
- 바닥이 거울에 반사되도록 하는 내용은 간단하다.
=> 기존 예제의 거울에 반사된 해골을 그리는 코드를 참고해서 값만 변경하면 된다.
- 문제는 거울에 반사된 해골의 그림자를 그리는 부분이다.
1. 그림자를 그릴 때 이중 혼합을 방지하기 위해 스텐실 버퍼를 이용해서 문제를 해결했다.
2. 거울에 반사된 그림을 그릴 때, 상이 거울 뒷편에도 생겨있지 않도록 하기 위해 스텐실 버퍼의 값이 1인 곳에만 그림이 그려지도록 설정했다.
위 2가지 경우에 각각 다른 Depth/Stencil 상태를 설정하는데 거울에 반사된 그림자를 그리려면 위 2가지 상태를 모두 적용해야 한다.
=> 이 부분을 어떻게 해야할지 찾지 못함. 현재는 거울에 반사된 그림자는 뭉개지는 현상이 발생하고, 제대로 그려지는 그림자는 거울 뒷편에 그려져서 거울에 반사되는 느낌이 없음.
=> 공부하면서 방법이 떠오르면 그때 다시 해결해보자
- 해결
- 기존에 사용되던 스텐실 버퍼를 그대로 이용하는게 아니라 새로운 스텐실 버퍼 상태를 설정해주면 되는 것이었음.
=> 거울에 반사된 그림자를 그리면서 깊이/스텐실 판정을 통과한 스텐실 버퍼 값을 1씩 증가하도록 설정할 것이기 때문에, 반사된 물체들 중 그림자를 가장 마지막에 그려줘야 함.
==> StencilRef 값은 1, StencilFunc는 EQUAL로 설정하고 깊이/스텐실 판정을 통과한 스텐실 버퍼의 값들은 INCR로 1씩 증가하게 해두면, 그림자가 중첩되는 문제도 해결하고 거울에만 그려지도록 설정할 수 있음.
- D3D11_DEPTH_STENCIL_DESC 구조체의 StencilReadMask, StencilWriteMask 값은 설정을 안해주면 자동으로 0xff값으로 지정이 될 것이라 생각했는데 그게 아니었음.
=> 해당 값들 설정 안해주면 원하는 의도대로 실행이 안 되고, 해당 값들을 0xff로 설정해줘야만 원하는 값이 나옴.
==> 아무런 값 설정도 안 해주면 0x00으로 저장되는게 아닌가 싶음.
개인적으로 이해한 내용을 바탕으로 작성하였기 때문에 틀린 내용이 있을 수 있습니다. 참고하실 때 주의 해주세요.
틀린 부분이나 이상한 부분이 있으면 댓글로 편하게 지적해주세요.
감사합니다!
'DirectX11 > 코드정리' 카테고리의 다른 글
[DirectX11] 9장 혼합 연습문제 (0) | 2023.01.05 |
---|---|
[DirectX11] 8장 텍스처 연습문제 (0) | 2022.12.02 |
[DirectX11] 텍스처 예제 (0) | 2022.11.29 |
[DirectX11] 7장 연습문제 (0) | 2022.11.25 |
[DirectX11] 조명 예제 (0) | 2022.11.25 |
댓글