카메라변환, 즉 View
와 Projection
변환에 대해 알아보자. 이 두개의 요소 역시 Constant Buffer
를 활용해서 구현할 것이다. 이전까지의 Transform
변환은 로컬 공간에서의 모양을 결정하는 정점들이 월드 공간으로의 변환을 해주는 것이였다. 여기에 추가로 해주는 View
변환은 카메라 공간으로의 변환을 해주는 것이고, Projection
변환은 투영 공간으로의 변환을 해주는 것이다. 각각 어떤것인지 한 번 알아보자.
View 변환
View
변환은 카메라 공간으로의 변환을 해주는 것이라고 하였다.

View
변환 Matrix
는 카메라의 3가지 요소를 이용해서 만들 수 있다. EyePosition
, FocusPosition
, UpDirection
이다. 즉 카메라의 위치, 카메라가 바라보는 곳, 카메라의 위쪽 방향을 가지고 View Matrix를 생성할 수 있다. 이 부분은 DirectXTK
에 포함되어 있는 함수를 사용하기로 한다.
const matrix& viewMatrix = XMMatrixLookAtLH( EyePosition, FocusPosition, UpDirection );
XMMatrixLookAtLH
의 postfix는 LH
인데, 이 것은 LeftHand
즉, 왼손 좌표계 기준으로 생성하는 것이다. 결과적으로 위 그림처럼 물체가 카메라 공간 바깥에 있다면 보이지 않게 된다.
Projection 변환
Projection
변환은 투영 공간으로의 변환을 해주는 것이다. 투영 방법에는 Orthographic
과 Perspective
방식이 있는데 각각 직교 투영과 원근 투영이라 부른다. 직교 투영에 대해서는 나중에 한번 다시 다루기로 하고 이번에는 원근 투영에 대해서만 다룬다.

원근 투영은 원근감을 표현하기 위한 투영이다. 이 원근감은 시야 절두체라는 개념에 의해 표현된다. 원근 투영 공간을 위 그림처럼 시야 절두체 모양으로 바꿔볼 수 있는데 near
면에 가까운 물체( 녹색 )는 스크린에 가득차 보일것이고, far
면에 가까운 물체( 흰색 )는 스크린에서 작게 보일것이다. 두 물체가 같은 크기, 같은 모양이라도 카메라로부터의 거리에 따라 크기가 다르게 표현되는 것이다. 이 시야 절두체를 벗어난 물체는 렌더링 과정은 거치지만 결과적으로 클리핑처리되기 때문에 백 버퍼에서의 결과로는 보이지 않게 된다.
Perspective
변환 matrix
역시 DirectXTK
에 포함되어 있는 함수를 이용해서 생성할 수 있다.
const matrix& projectionMatrix = XMMatrixPerspectiveLH( ViewWidth, ViewHeight, NearZ, FarZ );
ViewWidth
, ViewHeight
는 near
면에 있는 크기의 너비와 높이이다.
CRVertex GCRVRect[ 4 ] =
{
{ .Position = CRVector( -0.5f, 0.5f, 0.0f )
{ .Position = CRVector( 0.5f, 0.5f, 0.0f )
{ .Position = CRVector( -0.5f, -0.5f, 0.0f )
{ .Position = CRVector( 0.5f, -0.5f, 0.0f )
};
정점들의 범위에 대입하면 이 사각형이 스크린에 보이려면 ViewWidth
, ViewHeight
는 0.5
크기의 수준이여야 한다는 뜻이다. 뷰포트 크기( 1920 * 1080 )로 지정하게 되면 이 사각형은 너무 작게 렌더링되어 보이지 않는다. 나는 FOV
( Field of View )를 사용하는 원근 투영을 할 것이므로 XMMatrixPerspectiveLH
대신 XMMatrixPerspectiveFovLH
를 사용한다.
const matrix& projectionMatrix = XMMatrixPerspectiveFovLH( FovAngleY, AspectRatio, NearZ, FarZ );
이 함수는 세로 범위의 시야각 값과 종횡비를 통해 near
면의 크기가 결정된다.
원근 투영에 대한 수학적 설명은 여기 링크에 자세히 설명되어 있다.
CRCamera
카메라 관련 클래스를 추가하였다. 이 클래스는 3D 공간에서의 Transform
정보를 가지며, 위에서 설명한 View
, Projection
매트릭스를 반환할 수 있도록 여러 프로퍼티들을 가진다.
EProjectionType ProjectionType = EProjectionType::Perspective;
CRVector LookAtDirection = CRVector::Forward;
CRVector Up = CRVector::Up;
float FieldOfView = 90.0f;
float ViewWidth = 1920.f;
float ViewHeight = 1080.f;
float NearDistance = 0.1f;
float FarDistance = 10000.f;
위와 같은 프로퍼티들이 있다. 이 프로퍼티들을 통해 변환에 사용할 View
, Projection
매트릭스를 반환한다.
CRMatrix CRCamera::GetViewMatrix() const
{
const CRVector& location = Transform.GetLocation();
const CRVector& lookAt = CRVector::Transform( LookAtDirection, Transform.GetRotation() );
return DirectX::XMMatrixLookAtLH( location, location + lookAt, Up );
}
View
매트릭스를 반환하는 함수이다. Transform
정보를 통해 이 카메라의 위치를 Eye
로 간주하고 카메라가 바라보는 방향을 회전시킨다. 이를 통해 View
변환 매트릭스를 반환한다.
CRMatrix CRCamera::GetProjectionMatrix() const
{
return DirectX::XMMatrixPerspectiveFovLH( DirectX::XMConvertToRadians( FieldOfView ), ViewWidth / ViewHeight, NearDistance, FarDistance );
}
Projection
변환 매트릭스는 따로 추가 가공하는 것은 없고 캐슁중인 카메라 프로퍼티를 통해 매트릭스를 생성하여 반환한다.
Constant Buffer 추가하기 ( CRD11BindingConstantBuffer )
Constant Buffer
관련 코드는 재사용성이 높아 템플릿 헬퍼 클래스를 하나 추가했었다.
template< typename T >
class CRD11BindingConstantBuffer
{
private:
CRName Name;
CRD11ConstantBufferWPtr ConstantBufferPtr;
ED11RenderingPipelineStage Stage = ED11RenderingPipelineStage::Max;
unsigned int Slot = 0;
}
위와 같은 프로퍼티를 가지며 템플릿 인자에 따라 버퍼의 내용을 업데이트하고 렌더링 파이프라인에 연결한다.
이 헬퍼 클래스를 이용해서 View
, Projection
매트릭스를 Constant Buffer
를 생성하고 연결할 것이다.
그 외 생성 및 렌더링 파이프라인 연결, 버퍼 내용 업데이트는 기존 [DirectX11] 12. 변환 – Constant Buffer에 대해 알아보자.에서 사용했던 코드들과 동일하다.
Renderer에서의 View, Projection Constant Buffer
View
, Projection
Constant Buffer는 렌더러의 특성에 따라갈 수 있으므로 렌더러 내부에서 버퍼를 선언하고 사용한다.
class CRD11Renderer : public ICRRHIRenderer
{
public:
struct CRViewProjection
{
CRMatrix View;
CRMatrix Projection;
};
private:
CRD11BindingConstantBuffer< CRViewProjection > ViewProjectionBuffer;
public:
virtual void UpdateViewProjectionBuffer( const CRMatrix& ViewMatrix, const CRMatrix& ProjectionMatrix )
{
CRViewProjection viewProjection;
viewProjection.View = ViewMatrix.Transpose();
viewProjection.Projection = ProjectionMatrix.Transpose();
ViewProjectionBuffer.Update( viewProjection );
}
카메라를 통해 View, Projection 매트릭스 업데이트
일단 카메라 초기화시 함께 View
, Projection
버퍼의 내용을 업데이트한다.
GCamera.Initialize( CRCamera::EProjectionType::Perspective, 90.0f, width, height, 0.1f, 1000.0f );
GCamera.SetLookAtDirection( 0.f, 0.f, 1.f );
GCamera.Transform.SetLocation( 0.f, 0.f, -15.5f );
GRHI.GetRenderer()->UpdateViewProjectionBuffer( GCamera.GetViewMatrix(), GCamera.GetProjectionMatrix() );
이 후에는 카메라 관련 프로퍼티들이 변경되었을 때 업데이트할 수 있도록 수정할 예정이다.
이전글 : [DirectX11] 14. ImGUI 설치하기
다음글 : [DirectX11] 16. FBX File로부터 모델 데이터 Import하기.