[DirectX12] 📂. Camera
DirectXTK의 SimpleMath를 활용하여 프로젝트 진행
- DX를 기반으로 추가적 수학함수를 제공한다.
🔷 Camera
- 카메라가 보는 시야의 결과물을 만든다.
1. Camera
1.1. Camera Class
- 카메라의 관점으로 좌표를 옮기는 ViewMatrix와 카메라가 보는 장면으로 좌표를 옮기는 ProjectionMatrix를 관리하는 클래스
- 카메라의 투영은 원근 투영과, 직교 투영으로 나눈다.
enum class PROJECTION_TYPE
{
PERSPECTIVE, // 원근 투영
ORTHOGRAPHIC, // 직교 투영
};
class Camera : public Component
{
...
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 = {}; // 투영 행렬
};
1) 카메라의 뷰행렬과 투영 행렬을 구한다.
// 뷰 행렬
_matView = GetGameObject()->GetTransform()->GetLocalToWorldMatrix().Invert();
float width = static_cast<float>(MyEngine->GetWindow().width);
float height = static_cast<float>(MyEngine->GetWindow().height);
// 투영 행렬
if (_type == PROJECTION_TYPE::PERSPECTIVE)
_matProjection = ::XMMatrixPerspectiveFovLH(_fov, width / height, _near, _far);
else
_matProjection = ::XMMatrixOrthographicLH(width * _scale, height * _scale, _near, _far);
2) 활성화 된 Scene의 GameObject들을 카메라의 관점에서 렌더링한다.
shared_ptr<Scene> scene = SceneManager::GetInstance()->GetActiveScene();
// TODO : Layer 구분
const vector<shared_ptr<GameObject>>& gameObjects = scene->GetGameObjects();
for (auto& gameObject : gameObjects)
{
if (gameObject->GetMeshRenderer() == nullptr)
continue;
GetGameObject()->GetTransform()->PushData();
gameObject->GetMeshRenderer()->Render();
}
1.2. KeyInputScript Class
- 키보드 입력에 따른 Transform을 변경하는 동작을 하는 스크립트
shared_ptr<Transform> transform = GetGameObject()->GetTransform();
Vec3 pos = transform->GetLocalPosition();
float deltaTime = Timer::GetInstance()->GetDeltaTime();
if (Input::GetInstance()->IsButtonPress(KEY_TYPE::W)) // 앞
pos += transform->GetLook() * _speed * deltaTime;
if (Input::GetInstance()->IsButtonPress(KEY_TYPE::S)) // 뒤
pos -= transform->GetLook() * _speed * deltaTime;
if (Input::GetInstance()->IsButtonPress(KEY_TYPE::A)) // 왼쪽
pos -= transform->GetRight() * _speed * deltaTime;
if (Input::GetInstance()->IsButtonPress(KEY_TYPE::D)) // 오른쪽
pos += transform->GetRight() * _speed * deltaTime;
if (Input::GetInstance()->IsButtonPress(KEY_TYPE::Q)) // 회전(위)
{
Vec3 rotation = transform->GetLocalRotation();
rotation.x -= deltaTime * 0.5f;
transform->SetLocalRotation(rotation);
}
if (Input::GetInstance()->IsButtonPress(KEY_TYPE::E)) // 회전(아래)
{
Vec3 rotation = transform->GetLocalRotation();
rotation.x += deltaTime * 0.5f;
transform->SetLocalRotation(rotation);
}
transform->SetLocalPosition(pos);
2. Component 파생 클래스 구체화
2.1. Transform Class
- Local의 Position, Rotation, Scale에 관한 벡터값, Local, World행렬을 관리하는 클래스
class Transform : public Component
{
...
private:
weak_ptr<Transform> _parent; // 현재 객제의 좌표에 기준이 되는 Transform
Vec3 _localPosition = {};
Vec3 _localRotation = {};
Vec3 _localScale = { 1.f, 1.f, 1.f };
Matrix _matLocal = {};
Matrix _matWorld = {};
};
1) 변경되는 값에 따라 SRT값과 Local, World행렬 값을 갱신한다.
Matrix matScale = Matrix::CreateScale(_localScale); // S
Matrix matRotation = Matrix::CreateRotationX(_localRotation.x);
matRotation *= Matrix::CreateRotationY(_localRotation.y);
matRotation *= Matrix::CreateRotationZ(_localRotation.z); // R
Matrix matTranslation = Matrix::CreateTranslation(_localPosition); // T
_matLocal = matScale * matRotation * matTranslation;
_matWorld = _matLocal;
shared_ptr<Transform> parent = GetParent().lock();
if (parent != nullptr)
_matWorld += parent->GetLocalToWorldMatrix();
2) Transform을 계산하여 CBV(b0)로 넘겨준다.
Matrix matWVP = _matWorld * matVP; // matVP : ViewMatrix, ProjectionMatrix를 합성한 값
MyEngine->GetConstantBuffer(CONSTANT_BUFFER_TYPE::TRANSFORM)->PushData(&matWVP, sizeof(matWVP));
2.2. MeshRenderer Class
- 기존과 같음
3. HLSL
cbuffer TRANSFORM_PARAMS : register(b0)
{
row_major matrix matWVP;
}
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;
}
댓글남기기