본 강의의 핵심은 GameObject의 렌더링 책임을 MeshRenderer 컴포넌트로 완전히 분리하고, Camera/Transform 데이터를 독립적으로 Shader에 전달하는 효율적 구조를 설계하는 데 있다.
유니티와 유사한 조합형(Component-Based) 아키텍처로 전환하며, Mesh(기하 정보)와 Material(렌더링 방식) 을 분리할 수 있는 기반을 구축한다.
또한 DirectX 11 렌더링 파이프라인을 기반으로, 셰이더 자원/버퍼 분리, 파이프라인 정보 통합 구조, GPU 전송 효율화 등을 실습한다.
GameObject가 MeshRenderer와 Transform을 조합하여 렌더링 흐름을 제어하는 방식
Update, Render 단계에서 컴포넌트 기반 객체가 어떻게 GPU에 데이터를 넘기고, 파이프라인을 통해 화면에 출력되는지
컴포넌트 기반 설계를 통해 Material, Shader, Texture의 분리 구조로 확장 가능성 확보
전체 흐름의 의존성, 생명주기, 데이터 전달 위치를 시각화
MeshRenderer는 GameObject에 부착되어 실제 물체를 GPU에 렌더링하는 컴포넌트이다.matWorld, matView, matProjection을 하나의 상수 버퍼(TransformData) 로 GPU에 전송했으나, 이는 비효율적이다.MeshFilter, MeshRenderer 개념을 통합하여, MeshRenderer 안에 Mesh와 Material 책임을 임시 통합하여 구현함.| 용어 | 설명 |
|---|---|
| MeshRenderer | 렌더링을 수행하는 컴포넌트. 파이프라인 설정, 셰이더, 버퍼 관리 |
| TransformData | 오브젝트의 월드 변환 행렬(matWorld)을 담는 구조체 |
| CameraData | 카메라의 View 및 Projection 행렬을 담는 구조체 |
| ConstantBuffer | CPU → GPU로 데이터를 전송하는 상수 버퍼 구조 |
| Shader Slot | 상수 버퍼가 Shader에 할당되는 위치 (예: register(b0)) |
| VertexBuffer/IndexBuffer | 정점 및 인덱스 데이터를 GPU에 전달하는 버퍼 |
| InputLayout | 정점 구조(포맷)를 GPU 셰이더에 명시하는 설정 |
| SamplerState | 텍스처 샘플링 방식을 정의하는 GPU 상태 객체 |
| BlendState | 픽셀 색상 혼합 방식을 정의하는 GPU 상태 객체 |
Default.hlsl – 카메라/변환 행렬 분리cbuffer CameraData : register(b0)
{
row_major matrix matView;
row_major matrix matProjection;
};
cbuffer TransformData : register(b1)
{
row_major matrix matWorld;
};
b0: 카메라 전용 – 프레임마다 한 번만 전달b1: 오브젝트 전용 – 오브젝트마다 개별 전송Struct.h – C++ 구조체 정의struct CameraData
{
Matrix matView = Matrix::Identity;
Matrix matProjection = Matrix::Identity;
};
struct TransformData
{
Matrix matWorld = Matrix::Identity;
};
CameraData>, ConstantBuffer<TransformData> 로 생성됨MeshRenderer::MeshRenderer(ComPtr<ID3D11Device> device, ComPtr<ID3D11DeviceContext> deviceContext)
: Super(ComponentType::MeshRenderer), _device(device)
{
_geometry = make_shared<Geometry<VertexTextureData>>();
GeometryHelper::CreateRectangle(_geometry);
_vertexBuffer = make_shared<VertexBuffer>(device);
_vertexBuffer->Create(_geometry->GetVertices());
_indexBuffer = make_shared<IndexBuffer>(device);
_indexBuffer->Create(_geometry->GetIndices());
_vertexShader = make_shared<VertexShader>(device);
_vertexShader->Create(L"Default.hlsl", "VS", "vs_5_0");
_inputLayout = make_shared<InputLayout>(device);
_inputLayout->Create(VertexTextureData::descs, _vertexShader->GetBlob());
_pixelShader = make_shared<PixelShader>(device);
_pixelShader->Create(L"Default.hlsl", "PS", "ps_5_0");
_rasterizerState = make_shared<RasterizerState>(device);
_rasterizerState->Create();
_blendState = make_shared<BlendState>(device);
_blendState->Create();
_texture1 = make_shared<Texture>(device);
_texture1->Create(L"chiikawa.png");
_samplerState = make_shared<SamplerState>(device);
_samplerState->Create();
_cameraBuffer = make_shared<ConstantBuffer<CameraData>>(device, deviceContext);
_cameraBuffer->Create();
_transformBuffer = make_shared<ConstantBuffer<TransformData>>(device, deviceContext);
_transformBuffer->Create();
}
Update() – 카메라/월드 행렬 GPU 전송void MeshRenderer::Update()
{
_cameraData.matView = Camera::S_MatView;
_cameraData.matProjection = Camera::S_MatProjection;
_cameraBuffer->CopyData(_cameraData);
_transformData.matWorld = GetTransform()->GetWorldMatrix();
_transformBuffer->CopyData(_transformData);
}
Render() – 파이프라인 설정 및 렌더링void MeshRenderer::Render(shared_ptr<Pipeline> pipeline)
{
PipelineInfo info;
info.inputLayout = _inputLayout;
info.vertexShader = _vertexShader;
info.pixelShader = _pixelShader;
info.rasterizerState = _rasterizerState;
info.blendState = _blendState;
pipeline->UpdatePipeline(info);
pipeline->SetVertexBuffer(_vertexBuffer);
pipeline->SetIndexBuffer(_indexBuffer);
pipeline->SetConstantBuffer(0, SS_VertexShader, _cameraBuffer);
pipeline->SetConstantBuffer(1, SS_VertexShader, _transformBuffer);
pipeline->SetTexture(0, SS_PixelShader, _texture1);
pipeline->SetSamplerState(0, SS_PixelShader, _samplerState);
pipeline->DrawIndexed(_geometry->GetIndexCount(), 0, 0);
}
// Game.cpp
_monster = make_shared<GameObject>(...);
_monster->GetOrAddTransform(); // Transform 컴포넌트 기본 포함
_monster->AddComponent(make_shared<MeshRenderer>(device, deviceContext));
Transform, MeshRenderer, Camera 등의 기능은 모두 컴포넌트로 분리AddComponent<>(), GetComponent<>() 패턴을 그대로 반영void GameObject::Update()
{
if (GetCamera())
return; // 카메라는 Transform을 갱신하지 않음
_cameraData.matView = Camera::S_MatView;
_cameraData.matProjection = Camera::S_MatProjection;
_cameraBuffer->CopyData(_cameraData);
_transformData.matWorld = GetOrAddTransform()->GetWorldMatrix();
_transformBuffer->CopyData(_transformData);
}
// Game::Render()
_monster->GetMeshRenderer()->Render(_pipeline);
GetMeshRenderer()는 GameObject의 컴포넌트 관리 테이블에서 검색shared_ptr<MeshRenderer> 획득[GameObject]
└── [Transform 컴포넌트]
└── [MeshRenderer 컴포넌트]
└── Update() → GPU 버퍼 복사
└── Render() → Pipeline 구성 및 Draw
MeshRenderer가 소유MeshRenderer만이 GPU 파이프라인을 구성하고 Draw를 호출Transform은 World 행렬 제공, Camera는 View/Projection 행렬 제공MeshRenderer 내부에는 현재 Shader/Texture/Sampler 등이 전부 직접 포함되어 있음.
→ 이를 다음과 같이 Material 클래스로 추상화할 수 있음.
class Material
{
public:
shared_ptr<VertexShader> vertexShader;
shared_ptr<PixelShader> pixelShader;
shared_ptr<Texture> texture;
shared_ptr<SamplerState> sampler;
shared_ptr<BlendState> blendState;
};
class MeshRenderer : public Component
{
shared_ptr<Material> _material;
};
현재는 Default.hlsl 고정.
→ 향후 다양한 Shader 조합 지원을 위해, Shader 이름과 경로를 외부에서 설정 가능하게 설계 가능
_material->vertexShader->Create(L"MyShader.hlsl", "VS_Main", "vs_5_0");
_material->pixelShader->Create(L"MyShader.hlsl", "PS_Main", "ps_5_0");
| 컴포넌트 이름 | 책임 |
|---|---|
| Transform | 위치, 회전, 크기 등 공간 정보 제공 |
| MeshRenderer | 렌더링 책임 담당 |
| Camera | 뷰/투영 행렬 설정 |
| Material (추후) | Shader, Texture, 상태 객체 등 렌더링 세부 설정 |
| Animator (확장 예정) | 스켈레탈/스프라이트 애니메이션 처리 |
| Collider (확장 예정) | 충돌 영역 및 물리 엔진 연동 |
| 핵심 내용 | 설명 |
|---|---|
| ✅ 렌더링 책임 분리 | GameObject는 컴포넌트만 보유하고, 렌더링은 MeshRenderer가 수행 |
| ✅ 조합형 구조 | GameObject + MeshRenderer + Transform 조합으로 구성 |
| ✅ 행렬 분리 전송 | View/Projection은 한 번만 전송, World는 매 오브젝트 전송 |
| ✅ 파이프라인 구조화 | InputLayout, Shader, State 객체를 분리 관리하고 PipelineInfo로 구성 |
| ✅ 확장성 확보 | 추후 Material 컴포넌트, Shader/Texture 분리 가능하도록 설계 기반 구축 |
| ✅ 컴포넌트 조합 기반 구조 | GameObject는 Transform, MeshRenderer, Camera 등 컴포넌트를 조합 |
| ✅ GameObject는 컨테이너 | 내부에 렌더링/버퍼 관련 직접 처리 X |
| ✅ Render는 MeshRenderer 전담 | GameObject가 직접 렌더링하지 않고, 컴포넌트 위임 |
| ✅ 확장성 중심 설계 | Material, Shader 구조 분리, 다양한 셰이더 조합 지원 가능 |
| ✅ 유니티 구조와 유사 | MeshRenderer가 Shader, 텍스처 등 렌더링 책임을 독립적으로 관리 |