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(00.3f);
        material->SetFloat(10.4f);
        material->SetFloat(20.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

 

W // 앞
S // 뒤
A // 좌
D // 우

 

 

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

 

 

Rotation

 

Q
E

 

  • 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

+ Recent posts