이번에는 좌표계 변환 행렬을 이용해서 Camera를 만들어 볼 것이다.
벡터 계산 등을 위해 microsoft의 simpleMath 라이브러리를 이용한다.
VS_OUT VS_Main(VS_IN input)
{
VS_OUT output = (VS_OUT)0;
output.pos = mul(float4(input.pos, 1.f), matWVP);
output.color = input.color;
output.uv = input.uv;
return output;
}
Shader 코드에서 위치를 그대로 넘기는 것이 아닌 matWVP 행렬을 곱하는데, 이것은 Local 좌표에 World 변환 행렬, View 변환 행렬 , Projection 변환행렬을 곱하는 것과 같다.
class Camera : public Component
{
public:
Camera();
virtual ~Camera();
virtual void FinalUpdate() override;
void Render();
private:
PROJECTION_TYPE _type = PROJECTION_TYPE::PERSPECTIVE;
float _near = 1.f;
float _far = 1000.f;
float _fov = XM_PI / 4.f;
float _scale = 1.f;
Matrix _matView = {};
Matrix _matProjection = {};
public:
// TEMP
static Matrix S_MatView;
static Matrix S_MatProjection;
};
카메라의 Update는 다른 물체들 Update가 완료되고 마지막으로 실행되기 떄문에 FinalUpdate라는 이름을 붙여준다.
지금은 임시로 View 변환 행렬과 Projection 변환 행렬을 외부에서 사용 가능하게 static으로 들고 있는다.
void Camera::FinalUpdate()
{
_matView = GetTransform()->GetLocalToWorldMatrix().Invert();
float width = static_cast<float>(GEngine->GetWindow().width);
float height = static_cast<float>(GEngine->GetWindow().height);
if (_type == PROJECTION_TYPE::PERSPECTIVE)
_matProjection = ::XMMatrixPerspectiveFovLH(_fov, width / height, _near, _far);
else
_matProjection = ::XMMatrixOrthographicLH(width * _scale, height * _scale, _near, _far);
S_MatView = _matView;
S_MatProjection = _matProjection;
}
View 좌표계는 카메라의 Local 좌표계라고도 했다. 그렇기 때문에 _matView는 카메라의 World 행렬의 역행렬이다. (GetLocalToWorldMatrix() = _matWorld) 그리고 Projection 변환은 카메라의 타입에 따라 함수로 실행한다.
void Transform::FinalUpdate()
{
Matrix matScale = Matrix::CreateScale(_localScale);
Matrix matRotation = Matrix::CreateRotationX(_localRotation.x);
matRotation *= Matrix::CreateRotationY(_localRotation.y);
matRotation *= Matrix::CreateRotationZ(_localRotation.z);
Matrix matTranslation = Matrix::CreateTranslation(_localPosition);
_matLocal = matScale * matRotation * matTranslation;
_matWorld = _matLocal;
shared_ptr<Transform> parent = GetParent().lock();
if (parent != nullptr)
{
_matWorld *= parent->GetLocalToWorldMatrix();
}
}
Transform::FinalUpdate에서는 Scale, Rotation, Translation에 대하여 행렬을 만들어주고 S*R*T 순서로 곱해 Local 행렬을 구해준다. 부모가 없을 시 World 행렬이 Local 행렬이 되고 부모가 있을 시 Local 행렬에 부모의 world 행렬을 곱한 것이 World 행렬이 된다.
void TestCameraScript::LateUpdate()
{
Vec3 pos = GetTransform()->GetLocalPosition();
if (INPUT->GetButton(KEY_TYPE::W))
pos += GetTransform()->GetLook() * _speed * DELTA_TIME;
if (INPUT->GetButton(KEY_TYPE::S))
pos -= GetTransform()->GetLook() * _speed * DELTA_TIME;
if (INPUT->GetButton(KEY_TYPE::A))
pos -= GetTransform()->GetRight() * _speed * DELTA_TIME;
if (INPUT->GetButton(KEY_TYPE::D))
pos += GetTransform()->GetRight() * _speed * DELTA_TIME;
if (INPUT->GetButton(KEY_TYPE::Q))
{
Vec3 rotation = GetTransform()->GetLocalRotation();
rotation.x += DELTA_TIME * 0.5f;
GetTransform()->SetLocalRotation(rotation);
}
if (INPUT->GetButton(KEY_TYPE::E))
{
Vec3 rotation = GetTransform()->GetLocalRotation();
rotation.x -= DELTA_TIME * 0.5f;
GetTransform()->SetLocalRotation(rotation);
}
GetTransform()->SetLocalPosition(pos);
}
최종적으로 입력에 따라 카메라의 Transform, Rotation을 변경해 조정할 수 있다.
'그래픽스' 카테고리의 다른 글
| [DX12] Lighting 코드 #2 (0) | 2022.07.25 |
|---|---|
| [DX12] Lighting 코드 #1 (0) | 2022.07.25 |
| [DX12] Comoponent (0) | 2022.07.24 |
| [DX12] Material (0) | 2022.07.23 |
| [DX12] Depth Stencil View (0) | 2022.07.23 |