
- 월드에서 하늘을 담당하는 큰 박스
- 위 사진처럼 6면에 큰 그림을 붙여서 큐브형태로 조립해서 사용하는게 일반적
- 이번 예제에서는 큐브형태는 아니고 구 모양으로 만듦
스카이 박스의 좌표 변환
- 로컬 좌표에서 스카이박스의 중심점은 (0, 0)이다(당연한 얘기)
- 그런데 스카이박스는 말 그대로 배경의 역할을 하기 때문에 움직이거나 할 필요가 없음
- 그렇다고 가만히있어서 플레이어가 스카이박스의 끝에 닿는 일이 생기면 안되니까
- 뷰 좌표 (0, 0) 위치에 고정시키는 것은 어떨까 하는 아이디어
- 말 그대로 카메라를 따라다니는 것이다
- 그냥 (0, 0)에 있으면 되니까 World를 거쳐도, View에서 다시 (0, 0)이다.
- 그럼 굳이 World를 거칠 필요가 있을까? 그냥 View 좌표계로 바로 변환
- 따라서 이동에 대한 연산이 필요가 없으므로 T요소가 위치한 41, 42, 43 자리를 0으로 비워주면 되는데,
- 그러려면 (x, y, z, w)에서 w 자리에 방향벡터 변환할때마냥 0으로 두면 된다.
- 결론적으로 World를 건너뛰고 View만 곱해주는데 T는 무시하고 계산
*레스터라이저의 역할
- 버텍스쉐이더와 픽셀쉐이더 사이에 위치한 레스터라이저는
- 버텍스쉐이더가 각 정점에 대한 처리(정점을 이어서 삼각형을 그리는 등)을 하고 나면,
- 그 안의 픽셀을 찾아준 다음 그걸 픽셀 쉐이더에 넘겨준다 (보간하는 역할도 한다)
- 정점을 스킵할지 안할지도 레스터라이저에서 결정한다.
*정점을 스킵한다는게 무슨 소리인지?
- 삼각형을 그릴 때 정점의 순서가 시계방향으로 이루어져 있으면 그리고, 반시계방향이면 그리지 않는다.
- 그 이유는 우리가 넘겨준 정점들의 순서가 시계방향으로 삼각형을 이루는 경우 정면으로 본다면
- 반대로 뒤에서 봤을때는 그 순서가 반시계방향이 된다.
- 정면이면 그려지고, 후면이면 그려지지 않는데 이를 후면에 위치한 정점을 스킵한다고 표현한다.
- PIPELINE_DESCRIPTOR에서는 각 파이프라인에서 진행하는 공정에서의 상태를 지정해줄 수 있다.
- RasterizerState 멤버의 옵션으로 이를 설정해줄 수 있음.
switch (info.rasterizerType)
{
case RASTERIZER_TYPE::CULL_BACK:
_pipelineDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
_pipelineDesc.RasterizerState.CullMode = D3D12_CULL_MODE_BACK;
break;
case RASTERIZER_TYPE::CULL_FRONT:
_pipelineDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
_pipelineDesc.RasterizerState.CullMode = D3D12_CULL_MODE_FRONT;
break;
case RASTERIZER_TYPE::CULL_NONE:
_pipelineDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
_pipelineDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
break;
case RASTERIZER_TYPE::WIREFRAME:
_pipelineDesc.RasterizerState.FillMode = D3D12_FILL_MODE_WIREFRAME;
_pipelineDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
break;
}
- CullMode에서 이 옵션을 관리한다.
- 이것은 뒤에 있는 물체가 앞에 그려진 물체에 가려져있어서 그릴 필요가 없다는걸 빠르게 캐치하고 레스터라이저에서 처리하지 않고 폐기한다.
- 그런데 스카이박스는 안에 들어가서 뒷면을 봐도 보여야 한다.
- 이 때문에 별도의 쉐이더를 사용한다.
VS_OUT VS_Main(VS_IN input)
{
VS_OUT output = (VS_OUT)0;
// input.pos, 1 에서 1이 있는 이유는 좌표이기 때문
// 1이 아니라 0이면 방향만 추출
float4 viewPos = mul(float4(input.localPos, 0), g_matView);
float4 clipSpacePos = mul(viewPos, g_matProjection);
output.pos = clipSpacePos.xyww; // ww인 이유는 z를 w로 놓음으로서 1로 고정시키기 위해서
output.uv = input.uv;
return output;
}
float4 PS_Main(VS_OUT input) : SV_Target
{
float4 color = g_tex_0.Sample(g_sam_0, input.uv);
return color;
}
- 뷰 좌표계로 변환한 후 투영 행렬과 곱해주면 바로 투영 좌표로 변환되는게 아니라 클립 공간으로 바뀌는데,
- z값에 원래 0~1 사이의 값이 들어가게 되는데 z를 w로 두면 나중에 w로 일괄적으로 나눠질 때 z는 1이 된다.
(투영 변환 글 참고)
https://dev-treadmill.tistory.com/112
12. Projection, Screen 변환 행렬
투영 변환이란? - View 좌표계를 Projection 좌표계(NDC)로 변환하는 것 - 원근투영, 직교투영이 있으며 원근투영을 주로 사용 Near과 Far의 개념 near과 fat는 z축에 위치하며, 그 사이 범위의 z값을 가진
dev-treadmill.tistory.com
- 스카이박스가 맨 뒤에 그려지려면 깊이가 1이 되어야 하는데,
- 스카이 박스 깊이값을 1로 설정하면 그려지지 않는다.
- DepthStencilState의 비교연산이 LESS 상태이기 때문에 깊이 스탠실 버퍼 세팅값보다 작은 경우에만 그려지기 때문
- 이 부분을 수정해줘야 한다.
switch (info.depthStencilType)
{
case DEPTH_STENCIL_TYPE::LESS:
_pipelineDesc.DepthStencilState.DepthEnable = TRUE;
_pipelineDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
break;
case DEPTH_STENCIL_TYPE::LESS_EQUAL:
_pipelineDesc.DepthStencilState.DepthEnable = TRUE;
_pipelineDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
break;
case DEPTH_STENCIL_TYPE::GREATER:
_pipelineDesc.DepthStencilState.DepthEnable = TRUE;
_pipelineDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_GREATER;
break;
case DEPTH_STENCIL_TYPE::GREATER_EQUAL:
_pipelineDesc.DepthStencilState.DepthEnable = TRUE;
_pipelineDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_GREATER_EQUAL;
break;
}

'DirectX > [Inflearn_rookiss] Part2: DirectX12' 카테고리의 다른 글
20. Quaternion - 짐벌락 현상과 복소수에 대한 개념 (2) | 2023.01.30 |
---|---|
19. Frustum Culling (2) | 2023.01.28 |
17. Normal Mapping (0) | 2023.01.27 |
16. Lighting 구현 (0) | 2023.01.26 |
15. Lighting 기본 개념 (0) | 2023.01.25 |
댓글