02
23

상수 버퍼를 사용해서 셰이더에 원하는 어떤 변수든 넘겨줄 수 있지만

가장 큰 이점은 각 정점을 3D 공간으로 변환해주는 행렬을

넘겨줄 수 있는 것이라 생각한다.

그래서 그 공간 변환부터 정리해볼까 한다.

 

3D 렌더링 파이프라인

 

공간 변환 

출처 https://www.flipcode.com/archives/Geometry_Skinning_Blending_and_Vertex_Lighting-Using_Programmable_Vertex_Shaders_and_DirectX_80.shtml

 

한 정점이 렌더링이 되기까지의 렌더 파이프라인이다. 

정점이 입력되면, 월드 변환, 뷰 변환, 투영 변환, 뷰포트 변환을

거쳐 화면으로 출력이 된다.  이러한 파이프라인을 타는 이유는

3D로 계산된 물체가 화면에 출력되는 결과는 결국 2D이기 때문이다. 

 

로컬 좌표계, 모델 좌표계

 

박스 하나를 띄운다고 해보자. 박스는 정점 8개로 이루어져있다. 

박스의 각 정점들, 본인 고유 물체의 좌표를 로컬좌표계라고 한다.

 

 

월드 변환

 

로컬 좌표계 기준으로 박스 하나의 물체를 구성했다. 

기존과 같은 박스를 하나 더 출력한다 했을 때, 물체는 겹치게 될 것이다.

그래서 월드좌표계의 기준으로 정점을 변환한다. 월드 변환 행렬

Scale, Translation, Rotation

https://dlemrcnd.tistory.com/2?category=515796 

 

DirectX11 3D - 이동 행렬, 신축 행렬(스케일), 회전 행렬

1. 이동 행렬 (Translation Matrix) (x,y,z) 위치를 (tx, ty, yz)만큼 이동 _41, _42, _43의 행렬 요소를 곱한다. x+tx, y+ty, z+tz 다이렉트X에서 제공하는 함수는 다음과 같다. D3DXMATRIX matMatrix; D3DXMatr..

dlemrcnd.tistory.com

Translation matrix 이동행렬로 (월드 기준) 물체를 이동한다. 

 

뷰 변환

 

우리가 화면에서 물체를 보는 것은 카메라 방향이다. 

화면에 나오는 물체는 카메라 방향 카메라 기준으로 변환한다.

D3DXMatrixLookAtLH() 함수를 사용하면, 카메라 변환 행렬을 구할 수 있다. 

D3DXMATRIX* D3DXMatrixLookAtLH(
    _Inout_  D3DXMATRIX *pOut,  // 카메라 변환 행렬
    _In_     const D3DXVECTOR3 *pEye,   // 카메라 위치
    _In_     const D3DXVECTOR3 *pAt,    // 카메라가 바라보는 지점
    _In_     const D3DXVECTOR3 *pUp     // 카메라의 상향 벡터
    );

 

투영 변환

위까지는 3D 좌표계이지만, 디스플레이에서는 2D 화면이다.

https://www.labri.fr/perso/nrougier/teaching/opengl/

투영 변환은 절단된 사각뿔 모양의 프러스텀 뷰 볼륨(P) 또는 평행뷰볼륨(O)

를 사용해서, 시야의 near 가까운 면은 far 먼 면보다 작기 때문에

카메라에 가까운 개체를 확장하는 인간의 원근감을 유사하게 구현한다. 

옆에서 본 프러스텀 뷰 볼륨

시야각이 90도인 옆으로 본 프러스텀 뷰 볼륨이 있다.

원근법에서 카메라 룩 방향 Z축(카메라 깊이)에 반비례해서 작게 보여야한다.

x,y축을 z로 모두 나누면. z/y의 값이 1이 되는 부분이 있다. 

카메라 시야 범위 안 0~1로 카메라 밖에 있으면 보이지 않는 컬링이 된다.

원근감이 적용된 장면은 Left, Top Right, Bottom 즉, 정규화된 장치 좌표계(NDC)공간에

놓는 것이 투영 변환이다.

 

실제 2차원의 투영은 레스터화 단계에서 원근 나눗셈을 할때 된다. 

xyz 축 중에 z축을 제거하면 2D가 된다.

하지만 z축을 제거하면 깊이 정보가 소실되어, z버퍼가 필요하다. 

그래서 뎁스스텐실 작업을 따로 해주는 것이다. (깊이 버퍼용 텍스쳐 적용)

 

투영엔 두 종류가 있는데 일반적으로 원근 투영을 사용한다.

역시 행렬을 구해주는 함수가 Direct11 sdk에 포함되어 있다.

D3DXMATRIX* D3DXMatrixPerspectiveFovLH(
  _Inout_  D3DXMATRIX *pOut,  // 투영 변환 행렬
  _In_     FLOAT fovy,  // 시야각
  _In_     FLOAT Aspect, // 종횡비
  _In_     FLOAT zn,  // 가까운 평면의 z 값
  _In_     FLOAT zf   // 먼 평면의 z 값
);

 

화면좌표 변환

 

최종적으로 투영 변환 후에 윈도우의 어디쯤 출력한지 지정한다.

ID3D11DeviceContext::RSSetViewports로 RS에서 알아서 행렬이 곱해진다고

이해를 했다. 화면 크기를 윈도우 크기에 맞게 출력이 되어야 하기 때문에

RS에서 레스터라이져 단계에서 다렉 화면 크기를 설정해준다.

COMMENT