🎨DirectX

[DX] D3DXMatrixLookAtLH 함수(카메라, Viewer)

공대 컴린이 2023. 2. 4. 21:26
728x90

🎥 D3DXMatrixLookAtLH

D3DXMatrixLookAtLH 함수는 왼손 좌표계의 매트릭스를 작성하여 카메라를 다룰 수있도록 도와주는 함수이다.

 

D3DXMatrixLookAtLH 구문

  • pOut
    - out 시킬 매트릭스

    - 즉 작업의 결과인 D3DXMATRIX 구조체에 대한 포인터이다.
  • pEye
    - 볼 위치 (눈 지점)

    - 눈점을 의미하는 Vector3 구조체에 대한 포인터이다.
  • pAt
    - 볼 지점 (포커스 정도, 어디를 바라볼것인지)

    - 카메라를 찾는 대상을 정의하는 Vector3 구조체에 대한 포인터이다.
  • pUp
    - 윗쪽 방향

    - 현재 World의 최대를 정의하는 Vector3 구조체에 대한 포인터이다.

D3DXMatrixLookAtLH의 매개변수는 위와 같다.

pUp 매개변수는 카메라의 윗 방향을 나타내는 매개변수로, 일반적으로 [0, 1, 0]을 사용한다.

[0, 1, 0] 벡터를 사용한다는 의미는 camera가 roll 회전을 하지 않는다는 의미이다. 따라서 camera가 옆으로 기울어지거나 물구나무 선 듯 뒤집어져야 한다면, D3DXMatrixLookAtLH 함수를 사용하기 보다는 view 행렬을 일일이 만들어서 사용해야 한다.

📐 D3DXMatrixLookAtLH 함수 행렬 반환 공식

해당 함수의 반환값으로 Matrix (World)행렬이 나오는데, 해당 행렬 구성에 사용되는 수식을 자세히 살펴보자

 

반환된 행렬을 계산하는 함수 수식

zaxis = normal(At - Eye)

Z = At - Eye 는 Eye가 At을 바라보게하는 방향벡터 생성한다. 즉, 전방 방향의 생성이 성립되었다.
이때 보통 방향벡터는 크기가 1인 단위벡터를 사용하기 때문에 Normalize처리를 해줘야한다.
따라서 최종적으로Z = normal(At - Eye) 이 도출된다.

 xaxis = normal(cross(Up, zaxis))

X = cross(Up, Z(전방)) : cross는 외적을 의미한다.
따라서 Up(y)와 Z(전방)을 외적하면 왼손 좌표계를 통해 오른쪽 벡터가 나온다.

 yaxis = cross(zaxis, xaxis)

Y = cross(Z, X) : Z(전방)과 X(오른쪽)를 외적하면 수직(Up) 벡터가 나온다.

 

이때 함수의 매개변수로 이미 pUp(수직)방향 벡터를 전달했는데도 y축 벡터를 구하는 이유는 매개변수로 받은 Up벡터는 카메라에 대해 수직이고, 카메라가 회전하는 상황한다면 z축과 x축의 변화에 따라 카메라에 수직되는 y축 벡터가 변화될 수 있기 때문에 다시 구해줘야하는 것이다.

 

xx                     yx                     xz                     0
xy                     yy                     zy                     0
xz                     yz                     zz                     0
-dot(x, eye)    -dot(y, eye)      -dot(z, eye)       1          <--- 위치를 나타냄

이후 도출되는 Matrix 행렬의 위치 행렬 부분에는 특이하게 내적(dot)을 시켜서 위치를 구하였다.

(내적에 관한 내용은 수학공부 카테고리에서 다루었다)

 

dot(내적)값에 -(마이너스)를 붙인 이유는 고개를 오른쪽으로 돌리면 물체가 왼쪽으로 이동하는것처럼 보이고, 고개를 위로 올리면 물체가 아래로 이동하는 것처럼 보이는 원리를 이용하여 위치가 반대로 이동하도록 뒤집어 준 것이다.

 

내적(dot) : A . B = |A| |B| cos(@) = (Ax * Bx) + (Ay * By)

 

또한 내적 dot(x,y)는 x와 y의 성분을 곱하고 더하는 성질을 가지기 때문에, x가 y만큼 이동한다고 볼 수 있다.

따라서 dot(x, eye)는 x가 eye 지점을 포함하여 이동하는 것이다.

거기에 마이너스를 곱해 -dot(x, eye)한 결과는 반대로 eye에서 x쪽을 바라보는 것처럼, 즉 카메라의 시점처럼 방향이 전환된다.

 

결과적으로 카메라 회전에서 가장 중요한것은 방향을 구해내는 것과 위치를 구하는것이다.


📄 Camera.h

#pragma once

class Camera
{
public:
	Camera();
	virtual ~Camera();

	virtual void Update() = 0;

public:
	void Position(float x, float y, float z); // 위치를 설정하는 함수
	void Position(Vector3& vec); // 위치를 설정하는 함수
	void Position(Vector3* vec); // 위치를 Return하는 함수

	// 회전 각도 (Radian)
	void Rotation(float x, float y, float z);
	void Rotation(Vector3& vec);
	void Rotation(Vector3* vec);

	// 회전 각도 (Degree)
	void RotationDegree(float x, float y, float z);
	void RotationDegree(Vector3& vec);
	void RotationDegree(Vector3* vec);

	void GetMatrix(Matrix* matrix);

	Vector3 Forward() { return forward; }
	Vector3 Up() { return up; }
	Vector3 Right() { return right; }

protected:
	virtual void Rotation();
	virtual void Move();

protected:
	void View();

protected:
	Matrix matView; // 뷰 행렬

private:
	Vector3 position = Vector3(0, 0, 0);
	Vector3 rotation = Vector3(0, 0, 0);
	
	Vector3 forward = Vector3(0, 0, 1);
	Vector3 up = Vector3(0, 1, 0);
	Vector3 right = Vector3(1, 0, 0);

	Matrix matRotation; // 회전 행렬
};

📄 Camera.cpp

#include "Framework.h"
#include "Camera.h"

Camera::Camera()
{
	D3DXMatrixIdentity(&matRotation);
	D3DXMatrixIdentity(&matView);

	Rotation();
	Move();
}

Camera::~Camera()
{

}

void Camera::Position(float x, float y, float z)
{
	Position(Vector3(x, y, z));
}

void Camera::Position(Vector3 & vec)
{
	position = vec;

	Move();
}

void Camera::Position(Vector3 * vec)
{
	*vec = position;
}

void Camera::Rotation(float x, float y, float z)
{
	Rotation(Vector3(x, y, z));
}

void Camera::Rotation(Vector3 & vec)
{
	rotation = vec;

	Rotation();
}

void Camera::Rotation(Vector3 * vec)
{
	*vec = rotation;
}

void Camera::RotationDegree(float x, float y, float z)
{
	RotationDegree(Vector3(x, y, z));
}

void Camera::RotationDegree(Vector3 & vec)
{
	// Matrix에서는 라디안 각도를 사용해서 변환 과정이 필요함
	//rotation = vec * Math::PI / 180.0f;
	rotation = vec * 0.01745328f;

	Rotation();
}

void Camera::RotationDegree(Vector3 * vec)
{
	//*vec = rotation * 180.0f / Math::PI;
	*vec = rotation * 57.29577957f;
}

void Camera::GetMatrix(Matrix * matrix)
{
	// *matrix = matView; // 이것도 가능하지만 데이터 복사가 더 빠르다
	memcpy(matrix, &matView, sizeof(Matrix));
}

void Camera::Rotation()
{
	Matrix X, Y, Z;
	D3DXMatrixRotationX(&X, rotation.x);
	D3DXMatrixRotationY(&Y, rotation.y);
	D3DXMatrixRotationZ(&Z, rotation.z);

	matRotation = X * Y * Z;

	// 각 회전에 의한 forward, up, right를 구해서 적용하기
	D3DXVec3TransformNormal(&forward, &Vector3(0, 0, 1), &matRotation);
	D3DXVec3TransformNormal(&up, &Vector3(0, 1, 0), &matRotation);
	D3DXVec3TransformNormal(&right, &Vector3(1, 0, 0), &matRotation);

}

void Camera::Move()
{
	View();
}

void Camera::View()
{
	// D3DXMatrixLookAtLH 함수 사용!
	D3DXMatrixLookAtLH(&matView, &position, &(position + forward), &up);
}

 


참조

https://learn.microsoft.com/ko-kr/windows/win32/direct3d9/d3dxmatrixlookatlh

 

D3DXMatrixLookAtLH 함수(D3dx9math.h) - Win32 apps

D3DXMatrixLookAtLH 함수(D3dx9math.h) - 왼손 보기 행렬을 작성합니다.

learn.microsoft.com

 

728x90