Camera
- 카메라를 추가하여 Local -> World -> View -> Projection 변환을 수행한다.
- View 변환 행렬을 구할 땐 Camera Transform의 World 변환 행렬의 역행렬을 통해 구할 수 있다.
- 또 카메라에 따른 오브젝트의 이동을 구현한다.
Transform.h
더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#pragma once
#include "Component.h"
class Transform : public Component
{
public:
Transform();
virtual ~Transform();
virtual void FinalUpdate() override;
void PushData();
public:
// Parent 기준
const Vec3& GetLocalPosition() { return _localPosition; }
const Vec3& GetLocalRotation() { return _localRotation; }
const Vec3& GetLocalScale() { return _localScale; }
const Matrix& GetLocalToWorldMatrix() { return _matWorld; }
const Vec3& GetWorldPosition() { return _matWorld.Translation(); }
Vec3 GetRight() { return _matWorld.Right(); }
Vec3 GetUp() { return _matWorld.Up(); }
Vec3 GetLook() { return _matWorld.Backward(); }
void SetLocalPosition(const Vec3& position) { _localPosition = position; }
void SetLocalRotation(const Vec3& rotation) { _localRotation = rotation; }
void SetLocalScale(const Vec3& scale) { _localScale = scale; }
public:
void SetParent(shared_ptr<Transform> parent) { _parent = parent; }
weak_ptr<Transform> GetParent() { return _parent; }
private:
// Parent 기준
Vec3 _localPosition = {};
Vec3 _localRotation = {};
Vec3 _localScale = { 1.f, 1.f, 1.f };
Matrix _matLocal= {};
Matrix _matWorld = {};
weak_ptr<Transform> _parent;
};
|
cs |
- _matLocal = 부모님의 Local Space로 가기위한 행렬
- _matWorld = World Space로 가기위한 행렬.
- GetWolrdPosition() = _matWorld의 _41, _42, _43값을 토대로 World Space의 Position을 구함.
- Get Right, Up, Look() = World Space를 기준으로 한 Right, Up, Look Vector를 구함.
Transform.cpp
더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#include "pch.h"
#include "Transform.h"
#include "Engine.h"
#include "Camera.h"
Transform::Transform() : Component(COMPONENT_TYPE::TRANSFORM)
{
}
Transform::~Transform()
{
}
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();
}
}
void Transform::PushData()
{
Matrix matWVP = _matWorld * Camera::S_MatView * Camera::S_MatProjection;
CONST_BUFFER(CONSTANT_BUFFER_TYPE::TRANSFORM)->PushData(&matWVP, sizeof(matWVP));
}
|
cs |
- FinalUpdate() = SRT 행렬을 세팅해준 뒤 Local과 World로써 저장. 만약 부모 Transform이 존재한다면 _matWorld는 부모의 World로 교체 해준다.
- PushData() = WVP 행렬을 상수버퍼에 넘겨주는 역할
Cameara.h
더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
#pragma once
#include "Component.h"
enum class PROJECTION_TYPE
{
PERSPECTIVE, // 원근 투영
ORTHOGRAPHIC, // 직교 투영
};
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 / 3.f;
float _scale = 1.f;
Matrix _matView = {};
Matrix _matProjection = {};
public:
// TEMP
static Matrix S_MatView;
static Matrix S_MatProjection;
};
|
cs |
- near, far, fov, scale와 Camera Type을 각각 설정해준 뒤
- 자신의 View와 Projection 변환 행렬을 지닌다.
Camera.cpp
더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
#include "pch.h"
#include "Camera.h"
#include "Transform.h"
#include "Scene.h"
#include "SceneManager.h"
#include "GameObject.h"
#include "MeshRenderer.h"
#include "Engine.h"
Matrix Camera::S_MatView;
Matrix Camera::S_MatProjection;
Camera::Camera() : Component(COMPONENT_TYPE::CAMERA)
{
}
Camera::~Camera()
{
}
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;
}
void Camera::Render()
{
shared_ptr<Scene> scene = GET_SINGLE(SceneManager)->GetActiveScene();
// TODO : Layer 구분
const vector<shared_ptr<GameObject>>& gameObjects = scene->GetGameObjects();
for (auto& gameObject : gameObjects)
{
if (gameObject->GetMeshRenderer() == nullptr)
continue;
gameObject->GetMeshRenderer()->Render();
}
}
|
cs |
- FinalUpdate() = Local->World 변환 행렬의 역행렬을 구해줌으로써 View 행렬을 구해준 뒤, Camera Type에 따라 Screen의 비율에 맞게 Projection 행렬을 구해준다.
- Render() = 기존 Scene에서 Update 하던 부분을 이 곳에서 처리하게 되었다. Scene에 존재하는 Object들을 MeshRenderer를 통해 Render를 해주게 되는데, MeshRenderer의 Render() 함수는 mesh의 Render와 Material의 PushData를 해주게 된다.
GameObject.cpp
더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
#include "pch.h"
#include "GameObject.h"
#include "Transform.h"
#include "MeshRenderer.h"
#include "Camera.h"
#include "MonoBehaviour.h"
GameObject::GameObject()
{
}
GameObject::~GameObject()
{
}
void GameObject::Awake()
{
for (shared_ptr<Component>& component : _components)
{
if (component)
component->Awake();
}
for (shared_ptr<MonoBehaviour>& script : _scripts)
{
script->Awake();
}
}
void GameObject::Start()
{
for (shared_ptr<Component>& component : _components)
{
if (component)
component->Start();
}
for (shared_ptr<MonoBehaviour>& script : _scripts)
{
script->Start();
}
}
void GameObject::Update()
{
for (shared_ptr<Component>& component : _components)
{
if (component)
component->Update();
}
for (shared_ptr<MonoBehaviour>& script : _scripts)
{
script->Update();
}
}
void GameObject::LateUpdate()
{
for (shared_ptr<Component>& component : _components)
{
if (component)
component->LateUpdate();
}
for (shared_ptr<MonoBehaviour>& script : _scripts)
{
script->LateUpdate();
}
}
void GameObject::FinalUpdate()
{
for (shared_ptr<Component>& component : _components)
{
if (component)
component->FinalUpdate();
}
}
shared_ptr<Component> GameObject::GetFixedComponent(COMPONENT_TYPE type)
{
uint8 index = static_cast<uint8>(type);
assert(index < FIXED_COMPONENT_COUNT);
return _components[index];
}
shared_ptr<Transform> GameObject::GetTransform()
{
shared_ptr<Component> component = GetFixedComponent(COMPONENT_TYPE::TRANSFORM);
return static_pointer_cast<Transform>(component);
}
shared_ptr<MeshRenderer> GameObject::GetMeshRenderer()
{
shared_ptr<Component> component = GetFixedComponent(COMPONENT_TYPE::MESH_RENDERER);
return static_pointer_cast<MeshRenderer>(component);
}
shared_ptr<Camera> GameObject::GetCamera()
{
shared_ptr<Component> component = GetFixedComponent(COMPONENT_TYPE::CAMERA);
return static_pointer_cast<Camera>(component);
}
void GameObject::AddComponent(shared_ptr<Component> component)
{
component->SetGameObject(shared_from_this());
uint8 index = static_cast<uint8>(component->GetType());
if (index < FIXED_COMPONENT_COUNT)
{
_components[index] = component;
}
else
{
_scripts.push_back(dynamic_pointer_cast<MonoBehaviour>(component));
}
}
|
cs |
- GetFixedComponent() = Component Type을 입력하면 _components 배열에서 해당 Type의 Component Index를 참조하여 return 해준다.
- GetTransform , MeshRenderer, Camera = 각 Component를 GetFixedComponent()를 활용해서 return 해주는 역할.
SceneManager.cpp
더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
#include "pch.h"
#include "SceneManager.h"
#include "Scene.h"
#include "Engine.h"
#include "Material.h"
#include "GameObject.h"
#include "MeshRenderer.h"
#include "Transform.h"
#include "Camera.h"
#include "TestCameraScript.h"
void SceneManager::Update()
{
if (_activeScene == nullptr)
return;
_activeScene->Update();
_activeScene->LateUpdate();
_activeScene->FinalUpdate();
}
// TEMP
void SceneManager::Render()
{
if (_activeScene == nullptr)
return;
const vector<shared_ptr<GameObject>>& gameObjects = _activeScene->GetGameObjects();
for (auto& gameObject : gameObjects)
{
if (gameObject->GetCamera() == nullptr)
continue;
gameObject->GetCamera()->Render();
}
}
void SceneManager::LoadScene(wstring sceneName)
{
// TODO : 기존 Scene 정리
// TODO : 파일에서 Scene 정보 로드
_activeScene = LoadTestScene();
_activeScene->Awake();
_activeScene->Start();
}
shared_ptr<Scene> SceneManager::LoadTestScene()
{
shared_ptr<Scene> scene = make_shared<Scene>();
#pragma region TestObject
shared_ptr<GameObject> gameObject = make_shared<GameObject>();
vector<Vertex> vec(4);
vec[0].pos = Vec3(-0.5f, 0.5f, 0.5f);
vec[0].color = Vec4(1.f, 0.f, 0.f, 1.f);
vec[0].uv = Vec2(0.f, 0.f);
vec[1].pos = Vec3(0.5f, 0.5f, 0.5f);
vec[1].color = Vec4(0.f, 1.f, 0.f, 1.f);
vec[1].uv = Vec2(1.f, 0.f);
vec[2].pos = Vec3(0.5f, -0.5f, 0.5f);
vec[2].color = Vec4(0.f, 0.f, 1.f, 1.f);
vec[2].uv = Vec2(1.f, 1.f);
vec[3].pos = Vec3(-0.5f, -0.5f, 0.5f);
vec[3].color = Vec4(0.f, 1.f, 0.f, 1.f);
vec[3].uv = Vec2(0.f, 1.f);
vector<uint32> indexVec;
{
indexVec.push_back(0);
indexVec.push_back(1);
indexVec.push_back(2);
}
{
indexVec.push_back(0);
indexVec.push_back(2);
indexVec.push_back(3);
}
gameObject->AddComponent(make_shared<Transform>());
shared_ptr<Transform> transform = gameObject->GetTransform();
transform->SetLocalPosition(Vec3(0.f, 100.f, 200.f));
transform->SetLocalScale(Vec3(100.f, 100.f, 1.f));
shared_ptr<MeshRenderer> meshRenderer = make_shared<MeshRenderer>();
{
shared_ptr<Mesh> mesh = make_shared<Mesh>();
mesh->Init(vec, indexVec);
meshRenderer->SetMesh(mesh);
}
{
shared_ptr<Shader> shader = make_shared<Shader>();
shared_ptr<Texture> texture = make_shared<Texture>();
shader->Init(L"..\\Resources\\Shader\\default.hlsli");
texture->Init(L"..\\Resources\\Texture\\veigar.jpg");
shared_ptr<Material> material = make_shared<Material>();
material->SetShader(shader);
material->SetFloat(0, 0.3f);
material->SetFloat(1, 0.4f);
material->SetFloat(2, 0.3f);
material->SetTexture(0, texture);
meshRenderer->SetMaterial(material);
}
gameObject->AddComponent(meshRenderer);
scene->AddGameObject(gameObject);
#pragma endregion
#pragma region Camera
shared_ptr<GameObject> camera = make_shared<GameObject>();
camera->AddComponent(make_shared<Transform>());
camera->AddComponent(make_shared<Camera>()); // Near=1, Far=1000, FOV=45도
camera->AddComponent(make_shared<TestCameraScript>());
camera->GetTransform()->SetLocalPosition(Vec3(0.f, 100.f, 0.f));
scene->AddGameObject(camera);
#pragma endregion
return scene;
}
|
cs |
- Render() = 렌더링을 위한 임시적인 함수로, 활성화된 scene의 object들을 받은 뒤 camera의 render를 실행해주는 부분이다.
- LoadTestScene() = 우선 Object를 세팅할 때 Transform을 수동으로 생성하여 LocalPos와 Scale을 세팅해주는 부분이 추가되었다. 또 camera라는 object로써 생성해주어 transform, camera, script를 component로써 부착해주었으며 Post를 변경하여 Scene에 camera object를 추가해준다.
Default Shader
더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
cbuffer TRANSFORM_PARAMS : register(b0)
{
row_major matrix matWVP;
};
cbuffer MATERIAL_PARAMS : register(b1)
{
int int_0;
int int_1;
int int_2;
int int_3;
int int_4;
float float_0;
float float_1;
float float_2;
float float_3;
float float_4;
};
Texture2D tex_0 : register(t0);
Texture2D tex_1 : register(t1);
Texture2D tex_2 : register(t2);
Texture2D tex_3 : register(t3);
Texture2D tex_4 : register(t4);
SamplerState sam_0 : register(s0);
struct VS_IN
{
float3 pos : POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD;
};
struct VS_OUT
{
float4 pos : SV_Position;
float4 color : COLOR;
float2 uv : TEXCOORD;
};
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;
}
float4 PS_Main(VS_OUT input) : SV_Target
{
float4 color = tex_0.Sample(sam_0, input.uv);
return color;
}
|
cs |
- b0 레지스터의 상수버퍼가 기존의 float4가 아닌 WVP 행렬로 교체되었다.
- VS에서의 Pos 변경이 기존과는 달리 Input Pos에 WVP 행렬을 곱해주는 것을 볼 수 있다.
TestCameraScript.cpp
더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
#include "pch.h"
#include "TestCameraScript.h"
#include "Transform.h"
#include "Camera.h"
#include "GameObject.h"
#include "Input.h"
#include "Timer.h"
TestCameraScript::TestCameraScript()
{
}
TestCameraScript::~TestCameraScript()
{
}
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);
}
|
cs |
- MonoBehaviour를 상속받았으며 Input에 따라 카메라의 이동이나, 회전을 시켜주는 script.
- 앞뒤좌위 움직임이 가능하며, 고개를 들거나 숙이는것과 같이 x축에 대한 회전(Pitch)이 가능하다.
결과
기본 실행화면

Translation




- WASD 키 입력에 따라 앞, 뒤, 좌, 우로 카메라 이동이 가능하며, 카메라 이동의 반대로 오브젝트가 이동한다는것을 확인할 수 있다.
Rotation


- Q와 E 입력에 따라 Pitch 회전이 가능함을 볼 수 있다.
'Grahpics' 카테고리의 다른 글
[Graphics] DirectX12 - Lighting 개요 (0) | 2022.02.06 |
---|---|
[Graphics] DirectX12 - Resources (Cube & Sphere) (0) | 2022.02.05 |
[Graphics] DirectX12 - Scene (0) | 2022.01.31 |
[Graphics] DirectX12 - Component (0) | 2022.01.31 |
[Graphics] DirectX12 - Material (0) | 2022.01.30 |