*현재 Game.cpp를 여러 파일로 분리해놓은 상태
#pragma once
#include "pch.h"
/* GameObject
* : 3D 게임 오브젝트를 구성하는 기본 클래스
* 정점/인덱스 데이터, 버퍼, 셰이더, 텍스처, 렌더링 상태 등을 관리하고
* Update/Render 함수를 통해 매 프레임 업데이트 및 렌더링을 수행한다.
*/
class GameObject
{
public:
GameObject(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext);
~GameObject();
public:
void Update();
void Render(std::shared_ptr<Pipeline> pipeline);
private:
ComPtr<ID3D11Device> _device;
private:
/* 1. Geometry
: CPU 메모리 상에서 정점(Vertex)과 인덱스(Index) 데이터를 관리하는 객체 */
std::shared_ptr<Geometry<VertexTextureData>> _geometry;
/* 2. Vertex Buffer
: 정점(Vertex) 데이터를 GPU VRAM에 업로드하고, IA(Input Assembler) 단계에서 사용 */
std::shared_ptr<VertexBuffer> _vertexBuffer;
/* 3. Index Buffer
: 인덱스(Index) 데이터를 GPU VRAM에 업로드하고, IA(Input Assembler) 단계에서 사용 */
std::shared_ptr<IndexBuffer> _indexBuffer;
/* 4. Input Layout
: 정점 버퍼(Vertex Buffer)의 데이터 구조를 GPU(셰이더)에게 알려주기 위한 객체 */
std::shared_ptr<InputLayout> _inputLayout;
/* 5. Vertex Shader
: 정점 변환 단계 (월드/뷰/프로젝션 행렬 적용)에서 실행되는 셰이더 */
std::shared_ptr<VertexShader> _vertexShader;
/* 6. Constant Buffer
: IA(Input Assembler) 이후 VS(Vertex Shader)/PS(Pixel Shader) 단계에서 공통 데이터를 전달하는 용도 */
std::shared_ptr<ConstantBuffer<TransformData>> _constantBuffer;
/* 7. Rasterizer State
* : 삼각형을 화면에 어떻게 그릴지(채우기, 컬링 등) 설정하는 래스터라이저 상태 객체
*/
std::shared_ptr<RasterizerState> _rasterizerState;
/* 8. Pixel Shader
: 픽셀 색상 계산 단계 (텍스처, 라이팅 적용)에서 실행되는 셰이더 */
std::shared_ptr<PixelShader> _pixelShader;
/* 9. Shader Resource View
: 셰이더(Shader)가 GPU 리소스(텍스처, 버퍼 등)에 접근할 수 있도록 만들어주는 객체 */
std::shared_ptr<Texture> _shaderResoureView;
/* 10. Sampler State
* : 텍스처 좌표(UV) 샘플링 방식과 경계 처리 방식을 정의하는 샘플러 상태 객체
*/
std::shared_ptr<SamplerState> _samplerState;
/* 11. Blend State
* : 픽셀 색상 혼합(알파 블렌딩 등) 방식을 정의하는 블렌딩 상태 객체
*/
std::shared_ptr<BlendState> _blendState;
private:
/* Constant Buffer */
TransformData _transformData;
//ComPtr<ID3D11Buffer> _constantBuffer;
/* SRT */
Vec3 _localPosition = { 0.f, 0.f, 0.f };
Vec3 _localRotation = { 0.f, 0.f, 0.f };
Vec3 _localScale = { 1.f, 1.f, 1.f };
};
// GameObject.cpp
#include "pch.h"
#include "GameObject.h"
GameObject::GameObject(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext)
:_device(device)
{
// [1] Create Geometry (정점/인덱스 데이터 생성)
_geometry = std::make_shared<Geometry<VertexTextureData>>();
GeometryHelper::CreateRectangle(_geometry);
// [2] Create Vertex Buffer
_vertexBuffer = std::make_shared<VertexBuffer>(device);
_vertexBuffer->Create(_geometry->GetVertices());
// [3] Create Index Buffer
_indexBuffer = std::make_shared<IndexBuffer>(device);
_indexBuffer->Create(_geometry->GetIndices());
// [4] Create Vertex Shader
_vertexShader = std::make_shared<VertexShader>(device);
_vertexShader->Create(L"DefaultVertexShader.hlsl", "VS_main", "vs_5_0");
// [5] Create Input Layout
_inputLayout = std::make_shared<InputLayout>(device);
_inputLayout->Create(VertexTextureData::descs, _vertexShader->GetBlob());
// [6] Create Constant Buffer
_constantBuffer = std::make_shared<ConstantBuffer<TransformData>>(device, deviceContext);
_constantBuffer->CreateConstantBuffer();
// [7] Create Rasterizer State
_rasterizerState = std::make_shared<RasterizerState>(device);
_rasterizerState->CreateRasterizerState();
// [8] Create Pixel Shader
_pixelShader = std::make_shared<PixelShader>(device);
_pixelShader->Create(L"DefaultVertexShader.hlsl", "PS", "ps_5_0");
// [9] Create Shader Resource View (Texture)
_shaderResoureView = std::make_shared<Texture>(device);
_shaderResoureView->CreateShaderResourceView(L"hamster_latte.png");
// [10] Create Sampler State
_samplerState = std::make_shared<SamplerState>(device);
_samplerState->CreateSamplerState();
// [11] Create Blend State
_blendState = std::make_shared<BlendState>(device);
_blendState->CreateBlendState();
}
GameObject::~GameObject()
{
}
void GameObject::Update()
{
_localPosition.x += 0.001f;
// Create SRT
Matrix scaleMatrix = Matrix::CreateScale(_localScale / 3);
Matrix rotationMatrix = Matrix::CreateRotationX(_localRotation.x);
rotationMatrix *= Matrix::CreateRotationY(_localRotation.y);
rotationMatrix *= Matrix::CreateRotationZ(_localRotation.z);
Matrix translationMatrix = Matrix::CreateTranslation(_localPosition);
// Create WorldMatrix
Matrix worldMatrix = scaleMatrix * rotationMatrix * translationMatrix;
_transformData.worldMatrix = worldMatrix;
// 버퍼에 데이터 복사
_constantBuffer->CopyData(_transformData);
}
void GameObject::Render(std::shared_ptr<Pipeline> pipeline)
{
/* IA - VS - RS - PS - OM */
{
PipelineInfo info;
info._inputLayout = _inputLayout;
info._vertexShader = _vertexShader;
info._pixelShader = _pixelShader;
info._rasterizerState = _rasterizerState;
info._blendState = _blendState;
/*
- IA : GPU에게 정점 데이터의 구조 전달
: _graphics->GetDeviceContext()->IASetInputLayout(_inputLayout->GetComPtr().Get());
- IA : 각 정점을 어떻게 이어줄지 전달, 삼각형으로 이어주도록 설정
: _graphics->GetDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
- VS, PS : Vertex, Pixel Shader 설정
: _graphics->GetDeviceContext()->VSSetShader(_vertexShader->GetComPtr().Get(), nullptr, 0);
_graphics->GetDeviceContext()->PSSetShader(_pixelShader->GetComPtr().Get(), nullptr, 0);
- RS : 정점 → 픽셀로 삼각형 그리기
: _graphics->GetDeviceContext()->RSSetState(_rasterizerState->GetComPtr().Get());
- OM : Blend State
: _graphics->GetDeviceContext()->OMSetBlendState(_blendState->GetComPtr().Get(), _blendState->GetBlendFactor(), _blendState->GetSampleMask());
*/
pipeline->UpdatePipeline(info);
// IA (Input Assembler) : 정점의 정보 전달
/* GPU에게 정점 버퍼의 크기와 위치(stride, offset) 전달, vertices 사용함을 GPU에 알려줌 */
pipeline->SetVertexBuffer(_vertexBuffer);
/* 32-bit(4Byte) uint 인덱스 버퍼 GPU에 바인딩 */
pipeline->SetIndexBuffer(_indexBuffer);
// VS (Vertex Shader) : 정점의 위치/색상 등 가공
pipeline->SetConstantBuffer(0, SS_VertexShader, _constantBuffer);
// PS (Pixel Shader) : 픽셀 단위 색상 처리
pipeline->SetShaderResources(0, SS_PixelShader, _shaderResoureView);
pipeline->SetSamplerState(0, SS_PixelShader, _samplerState);
// OM (Output Merger) : 최종 픽셀을 렌더 타겟에 출력
pipeline->DrawIndexed(_geometry->GetIndexCount(), 0, 0);
}
}
이제 GameObject를 Component와 Transform으로 또 분리해야 함
#pragma once
#include "pch.h"
#include "Transform.h"
/* GameObject
* : 3D 게임 오브젝트를 구성하는 기본 클래스
* 정점/인덱스 데이터, 버퍼, 셰이더, 텍스처, 렌더링 상태 등을 관리하고
* Update/Render 함수를 통해 매 프레임 업데이트 및 렌더링을 수행한다.
*/
class GameObject
{
public:
GameObject(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext);
~GameObject();
public:
void Update();
void Render(std::shared_ptr<Pipeline> pipeline);
private:
ComPtr<ID3D11Device> _device;
private:
/* 1. Geometry
: CPU 메모리 상에서 정점(Vertex)과 인덱스(Index) 데이터를 관리하는 객체 */
std::shared_ptr<Geometry<VertexTextureData>> _geometry;
/* 2. Vertex Buffer
: 정점(Vertex) 데이터를 GPU VRAM에 업로드하고, IA(Input Assembler) 단계에서 사용 */
std::shared_ptr<VertexBuffer> _vertexBuffer;
/* 3. Index Buffer
: 인덱스(Index) 데이터를 GPU VRAM에 업로드하고, IA(Input Assembler) 단계에서 사용 */
std::shared_ptr<IndexBuffer> _indexBuffer;
/* 4. Input Layout
: 정점 버퍼(Vertex Buffer)의 데이터 구조를 GPU(셰이더)에게 알려주기 위한 객체 */
std::shared_ptr<InputLayout> _inputLayout;
/* 5. Vertex Shader
: 정점 변환 단계 (월드/뷰/프로젝션 행렬 적용)에서 실행되는 셰이더 */
std::shared_ptr<VertexShader> _vertexShader;
/* 6. Constant Buffer
: IA(Input Assembler) 이후 VS(Vertex Shader)/PS(Pixel Shader) 단계에서 공통 데이터를 전달하는 용도 */
std::shared_ptr<ConstantBuffer<TransformData>> _constantBuffer;
/* 7. Rasterizer State
* : 삼각형을 화면에 어떻게 그릴지(채우기, 컬링 등) 설정하는 래스터라이저 상태 객체
*/
std::shared_ptr<RasterizerState> _rasterizerState;
/* 8. Pixel Shader
: 픽셀 색상 계산 단계 (텍스처, 라이팅 적용)에서 실행되는 셰이더 */
std::shared_ptr<PixelShader> _pixelShader;
/* 9. Shader Resource View
: 셰이더(Shader)가 GPU 리소스(텍스처, 버퍼 등)에 접근할 수 있도록 만들어주는 객체 */
std::shared_ptr<Texture> _shaderResoureView;
/* 10. Sampler State
* : 텍스처 좌표(UV) 샘플링 방식과 경계 처리 방식을 정의하는 샘플러 상태 객체
*/
std::shared_ptr<SamplerState> _samplerState;
/* 11. Blend State
* : 픽셀 색상 혼합(알파 블렌딩 등) 방식을 정의하는 블렌딩 상태 객체
*/
std::shared_ptr<BlendState> _blendState;
private:
/* Constant Buffer */
TransformData _transformData;
//ComPtr<ID3D11Buffer> _constantBuffer;
std::shared_ptr<Transform> _transform = std::make_shared<Transform>();
std::shared_ptr<Transform> _parent = std::make_shared<Transform>();
};
// GameObject.cpp
#include "pch.h"
#include "GameObject.h"
GameObject::GameObject(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext)
:_device(device)
{
// [1] Create Geometry (정점/인덱스 데이터 생성)
_geometry = std::make_shared<Geometry<VertexTextureData>>();
GeometryHelper::CreateRectangle(_geometry);
// [2] Create Vertex Buffer
_vertexBuffer = std::make_shared<VertexBuffer>(device);
_vertexBuffer->Create(_geometry->GetVertices());
// [3] Create Index Buffer
_indexBuffer = std::make_shared<IndexBuffer>(device);
_indexBuffer->Create(_geometry->GetIndices());
// [4] Create Vertex Shader
_vertexShader = std::make_shared<VertexShader>(device);
_vertexShader->Create(L"DefaultVertexShader.hlsl", "VS_main", "vs_5_0");
// [5] Create Input Layout
_inputLayout = std::make_shared<InputLayout>(device);
_inputLayout->Create(VertexTextureData::descs, _vertexShader->GetBlob());
// [6] Create Constant Buffer
_constantBuffer = std::make_shared<ConstantBuffer<TransformData>>(device, deviceContext);
_constantBuffer->CreateConstantBuffer();
// [7] Create Rasterizer State
_rasterizerState = std::make_shared<RasterizerState>(device);
_rasterizerState->CreateRasterizerState();
// [8] Create Pixel Shader
_pixelShader = std::make_shared<PixelShader>(device);
_pixelShader->Create(L"DefaultVertexShader.hlsl", "PS", "ps_5_0");
// [9] Create Shader Resource View (Texture)
_shaderResoureView = std::make_shared<Texture>(device);
_shaderResoureView->CreateShaderResourceView(L"hamster_latte.png");
// [10] Create Sampler State
_samplerState = std::make_shared<SamplerState>(device);
_samplerState->CreateSamplerState();
// [11] Create Blend State
_blendState = std::make_shared<BlendState>(device);
_blendState->CreateBlendState();
_parent->AddChild(_transform);
_transform->SetParent(_parent);
}
GameObject::~GameObject()
{
}
void GameObject::Update()
{
// 부모 값을 변경하면 자식의 pos, rot, scale 값이 변경되는지 확인
Vec3 pos = _parent->GetPosition();
pos.x += 0.001f;
_parent->SetPosition(pos);
Vec3 rot = _parent->GetRotation();
rot.z += 0.01f;
_parent->SetRotation(rot);
Vec3 scale = _parent->GetScale();
scale.x /= 1.001f;
scale.y /= 1.001f;
_parent->SetScale(scale);
// Create WorldMatrix
_transformData.worldMatrix = _transform->GetWorldMatrix();
// 버퍼에 데이터 복사
_constantBuffer->CopyData(_transformData);
}
void GameObject::Render(std::shared_ptr<Pipeline> pipeline)
{
/* IA - VS - RS - PS - OM */
{
PipelineInfo info;
info._inputLayout = _inputLayout;
info._vertexShader = _vertexShader;
info._pixelShader = _pixelShader;
info._rasterizerState = _rasterizerState;
info._blendState = _blendState;
/*
- IA : GPU에게 정점 데이터의 구조 전달
: _graphics->GetDeviceContext()->IASetInputLayout(_inputLayout->GetComPtr().Get());
- IA : 각 정점을 어떻게 이어줄지 전달, 삼각형으로 이어주도록 설정
: _graphics->GetDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
- VS, PS : Vertex, Pixel Shader 설정
: _graphics->GetDeviceContext()->VSSetShader(_vertexShader->GetComPtr().Get(), nullptr, 0);
_graphics->GetDeviceContext()->PSSetShader(_pixelShader->GetComPtr().Get(), nullptr, 0);
- RS : 정점 → 픽셀로 삼각형 그리기
: _graphics->GetDeviceContext()->RSSetState(_rasterizerState->GetComPtr().Get());
- OM : Blend State
: _graphics->GetDeviceContext()->OMSetBlendState(_blendState->GetComPtr().Get(), _blendState->GetBlendFactor(), _blendState->GetSampleMask());
*/
pipeline->UpdatePipeline(info);
// IA (Input Assembler) : 정점의 정보 전달
/* GPU에게 정점 버퍼의 크기와 위치(stride, offset) 전달, vertices 사용함을 GPU에 알려줌 */
pipeline->SetVertexBuffer(_vertexBuffer);
/* 32-bit(4Byte) uint 인덱스 버퍼 GPU에 바인딩 */
pipeline->SetIndexBuffer(_indexBuffer);
// VS (Vertex Shader) : 정점의 위치/색상 등 가공
pipeline->SetConstantBuffer(0, SS_VertexShader, _constantBuffer);
// PS (Pixel Shader) : 픽셀 단위 색상 처리
pipeline->SetShaderResources(0, SS_PixelShader, _shaderResoureView);
pipeline->SetSamplerState(0, SS_PixelShader, _samplerState);
// OM (Output Merger) : 최종 픽셀을 렌더 타겟에 출력
pipeline->DrawIndexed(_geometry->GetIndexCount(), 0, 0);
}
}
#pragma once
class GameObject;
class Component
{
public:
Component();
~Component();
virtual void Init() abstract;
virtual void Update() abstract;
std::shared_ptr<GameObject> GetGameObject() { return _owner; }
private:
std::shared_ptr<GameObject> _owner;
};
아직 Component는 건드리지 않음
#pragma once
#include "Component.h"
class Transform : public Component
{
public:
Transform();
~Transform();
public:
virtual void Init() override;
virtual void Update() override;
void UpdateTransform();
// Local
Vec3 GetLocalScale() { return _localScale; }
void SetLocalScale(const Vec3& localScale) { _localScale = localScale; UpdateTransform(); }
Vec3 GetLocalRotation() { return _localRotation; }
void SetLocalRotation(const Vec3& localRotation) { _localRotation = localRotation; UpdateTransform();}
Vec3 GetLocalPosition() { return _localPosition; }
void SetLocalPosition(const Vec3& localPosition) { _localPosition = localPosition; UpdateTransform(); }
// World
Vec3 GetScale() { return _scale; }
void SetScale(const Vec3& worldScale);
Vec3 GetRotation() { return _rotation; }
void SetRotation(const Vec3& worldRotation);
Vec3 GetPosition() { return _position; }
void SetPosition(const Vec3& worldPosition);
// object의 world 변환 행렬
Matrix GetWorldMatrix() { return _worldMatrix; }
Vec3 QuaternionToEulerAngles(Quaternion q);
public:
bool HasParent() { return _parent != nullptr; }
std::shared_ptr<Transform> GetParent() { return _parent; }
void SetParent(std::shared_ptr<Transform> parent) { _parent = parent; }
const std::vector<std::shared_ptr<Transform>> GetChildren() { return _children; }
void AddChild(std::shared_ptr<Transform> child) { _children.push_back(child); }
private:
/* SRT */
Vec3 _localPosition = { 0.f, 0.f, 0.f };
Vec3 _localRotation = { 0.f, 0.f, 0.f };
Vec3 _localScale = { 1.f, 1.f, 1.f };
Matrix _localMatrix = Matrix::Identity;
Matrix _worldMatrix = Matrix::Identity;
// Cache
Vec3 _scale;
Vec3 _rotation;
Vec3 _position;
Vec3 _right;
Vec3 _up;
Vec3 _look;
private:
std::shared_ptr<Transform> _parent;
std::vector<std::shared_ptr<Transform>> _children;
};
// Transform.cpp
#include "pch.h"
#include "Transform.h"
Transform::Transform()
{
}
Transform::~Transform()
{
}
void Transform::Init()
{
}
void Transform::Update()
{
}
void Transform::UpdateTransform()
{
// Create SRT
Matrix scaleMatrix = Matrix::CreateScale(_localScale);
Matrix rotationMatrix = Matrix::CreateRotationX(_localRotation.x);
rotationMatrix *= Matrix::CreateRotationY(_localRotation.y);
rotationMatrix *= Matrix::CreateRotationZ(_localRotation.z);
Matrix translationMatrix = Matrix::CreateTranslation(_localPosition);
_localMatrix = scaleMatrix * rotationMatrix * translationMatrix;
if (HasParent())
{
// 부모가 있는 경우 -> 부모의 world 변환 행렬 필요
_worldMatrix = _localMatrix * _parent->GetWorldMatrix();
}
else
{
// 부모가 없는 경우
_worldMatrix = _localMatrix;
}
// 짐벌락 해결 위해 Quaternion 사용
Quaternion quaternion;
// world행렬 srt로 분해
_worldMatrix.Decompose(_scale, quaternion, _position);
_rotation = QuaternionToEulerAngles(quaternion);
// vector 방향만, 위치 필요하면 transformcoord
_right = Vec3::TransformNormal(Vec3::Right, _worldMatrix);
_up = Vec3::TransformNormal(Vec3::Up, _worldMatrix);
// library에 forward, backward 반대로 되어있음
_look = Vec3::TransformNormal(Vec3::Backward, _worldMatrix);
// children에서도 함수 재귀적 호출
for (const std::shared_ptr<Transform>& child : _children)
{
child->UpdateTransform();
}
}
void Transform::SetScale(const Vec3& worldScale)
{
if (HasParent())
{
// 크기가 4x4x4인 오브젝트A가 크기 2x2x2인 오브젝트B의 자식으로 설정되면, A의 크기는 2x2x2로 설정됨
Vec3 parentScale = _parent->GetScale();
Vec3 scale = worldScale;
scale.x /= parentScale.x;
scale.y /= parentScale.y;
scale.z /= parentScale.z;
SetLocalScale(scale);
}
else
{
SetLocalScale(worldScale);
}
}
void Transform::SetRotation(const Vec3& worldRotation)
{
if (HasParent())
{
Matrix inverseMatrix = _parent->GetWorldMatrix().Invert();
Vec3 rotation;
rotation.TransformNormal(worldRotation, inverseMatrix);
SetLocalRotation(rotation);
}
else
{
SetLocalRotation(worldRotation);
}
}
void Transform::SetPosition(const Vec3& worldPosition)
{
if (HasParent())
{
// 부모의 local->world 변환 행렬의 역행렬 = world 좌표에 있던 오브젝트를 부모 기준 좌표로 변환
Matrix worldToParentLocalMatrix = _parent->GetWorldMatrix().Invert();
Vec3 position;
position.Transform(worldPosition, worldToParentLocalMatrix);
SetLocalPosition(position);
}
else
{
SetLocalPosition(worldPosition);
}
}
Vec3 Transform::QuaternionToEulerAngles(Quaternion q)
{
Vec3 angles;
// roll (x-axis rotation)
double sinr_cosp = 2 * (q.w * q.x + q.y * q.z);
double cosr_cosp = 1 - 2 * (q.x * q.x + q.y * q.y);
angles.x = std::atan2(sinr_cosp, cosr_cosp);
// pitch (y-axis rotation)
double sinp = std::sqrt(1 + 2 * (q.w * q.y - q.x * q.z));
double cosp = std::sqrt(1 - 2 * (q.w * q.y - q.x * q.z));
angles.y = 2 * std::atan2(sinp, cosp) - 3.14159f / 2;
// yaw (z-axis rotation)
double siny_cosp = 2 * (q.w * q.z + q.x * q.y);
double cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z);
angles.z = std::atan2(siny_cosp, cosy_cosp);
return angles;
}
'게임개발 > Graphics' 카테고리의 다른 글
[Graphics] SimpleMath 실습 (0) | 2025.04.26 |
---|---|
[Graphics] SimpleMath (0) | 2025.04.21 |
[Graphics] 행렬 (0) | 2025.04.21 |
[Graphics] RasterizerState, SampleState, BlendState (0) | 2025.04.10 |
[Graphics] Constant Buffer (0) | 2025.04.07 |