수업


📌 주제

  • Material과 Mesh 시스템의 분리 및 통합 구조 설계

  • 기존 MeshRenderer 내부에 혼재되어 있던 렌더링 요소(정점 버퍼, 인덱스 버퍼, 셰이더, 텍스처 등)를 명확하게 역할별로 분리하여 각각 Mesh, Shader, Material 클래스로 나누고, 이들을 모두 ResourceManager를 통해 중앙 관리하는 구조를 만드는 것입니다.

  • Unity와 유사한 Component 기반 조립형 렌더링 구조를 실현하고, 유지보수성과 재사용성을 극대화합니다.


📖 개념 정리

✅ Mesh (메쉬)

  • 물체의 기하학적 구조(모양)를 나타냅니다.
  • 정점(Vertex)과 인덱스(Index) 데이터를 포함하며, GPU에서 도형을 그릴 수 있게 합니다.
  • 내부적으로 Geometry, VertexBuffer, IndexBuffer를 사용합니다.

✅ Material (재질)

  • 물체가 어떤 시각적 특성을 가질지를 정의합니다.
  • 내부에 Shader, Texture를 포함하고 있으며, 이후 Lighting, Animation 등으로 확장됩니다.
  • 다양한 오브젝트들이 하나의 Material을 공유할 수 있어 메모리 사용이 효율적입니다.

✅ Shader (셰이더)

  • GPU에서 실행되는 프로그램입니다.
  • 정점 처리용 VertexShader, 픽셀 처리용 PixelShader, 정점 구조 정의용 InputLayout으로 구성됩니다.
  • 렌더링 결과물의 색상, 질감, 조명 효과 등을 결정합니다.

✅ ResourceManager

  • Mesh, Material, Shader, Texture와 같은 리소스를 이름 기반(Key)으로 중앙에서 관리합니다.
  • 중복 생성을 방지하며, 필요한 곳에서 빠르게 참조 가능하게 합니다.

📌 용어 정리

용어설명
Mesh물체의 기하 구조 (정점 + 인덱스)
Material시각적 특성 정의 (Shader + Texture)
ShaderGPU 프로그램 (VS + PS + InputLayout)
VertexBuffer정점 정보를 담은 GPU 버퍼
IndexBuffer도형 그리기 순서를 담은 GPU 버퍼
InputLayout정점 데이터의 구성 정의
ResourceManager리소스 생성 및 이름 기반 조회 담당
MeshRendererMesh와 Material을 보유하며 렌더링 수행
Pipeline렌더링 명령 수행 클래스

⚙️ 코드 구조 분석

📌 1. 기존 MeshRenderer의 구조

// 분리 전 구조
shared_ptr<Geometry<VertexTextureData>> _geometry;
shared_ptr<VertexBuffer> _vertexBuffer;
shared_ptr<IndexBuffer> _indexBuffer;

➡️ 이 구조는 기하정보와 렌더링 버퍼가 모두 MeshRenderer에 포함되어 있어 응집도가 낮음. 이들을 Mesh 클래스로 추출하여 독립적 관리가 가능하게 함.


📌 2. Mesh 클래스 선언 및 구현

class Mesh : public ResourceBase
{
public:
	Mesh(ComPtr<ID3D11Device> device);
	virtual ~Mesh();

	void CreateDefaultRectangle();

	shared_ptr<VertexBuffer> GetVertexBuffer();
	shared_ptr<IndexBuffer> GetIndexBuffer();

private:
	ComPtr<ID3D11Device> _device;
	shared_ptr<Geometry<VertexTextureData>> _geometry;
	shared_ptr<VertexBuffer> _vertexBuffer;
	shared_ptr<IndexBuffer> _indexBuffer;
};

➤ 생성자 & 기본 도형 초기화

void Mesh::CreateDefaultRectangle()
{
	_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());
}
  • 사각형 정점/인덱스 데이터를 생성 후, GPU에 업로드할 VertexBuffer, IndexBuffer를 생성.

📌 3. MeshRenderer에서 Mesh 통합 적용

shared_ptr<Mesh> _mesh;

void SetMesh(shared_ptr<Mesh> mesh) { _mesh = mesh; }
shared_ptr<Mesh> GetMesh() { return _mesh; }

➡️ Mesh를 내부 필드로 보관하고, 외부에서 설정/접근 가능한 구조로 변경.


📌 4. RenderManager에서 Mesh 접근 방식 변경

_pipeline->SetVertexBuffer(meshRenderer->GetMesh()->GetVertexBuffer());
_pipeline->SetIndexBuffer(meshRenderer->GetMesh()->GetIndexBuffer());
_pipeline->DrawIndexed(meshRenderer->GetMesh()->GetIndexBuffer()->GetCount(), 0, 0);

➡️ 더 이상 _vertexBuffer, _indexBuffer를 직접 접근하지 않고, Mesh 객체를 통해 버퍼 정보를 얻음.


📌 5. ResourceManager에서 기본 Mesh 생성 및 등록

void ResourceManager::CreateDefaultMesh()
{
	auto mesh = make_shared<Mesh>(_device);
	mesh->SetName(L"Rectangle");
	mesh->CreateDefaultRectangle();
	Add(mesh->GetName(), mesh);
}

➡️ "Rectangle"이라는 이름으로 사각형 Mesh를 생성하고 ResourceManager에 등록.


📌 6. SceneManager에서 Mesh 세팅

auto mesh = RESOURCES->Get<Mesh>(L"Rectangle");
meshRenderer->SetMesh(mesh);

➡️ SceneManager는 ResourceManager에서 Mesh를 가져와 MeshRenderer에 세팅.


📌 7. Shader 클래스 정의

class Shader : public ResourceBase
{
public:
	Shader();
	virtual ~Shader();

	shared_ptr<InputLayout> GetInputLayout();
	shared_ptr<VertexShader> GetVertexShader();
	shared_ptr<PixelShader> GetPixelShader();

private:
	friend class ResourceManager;

	shared_ptr<InputLayout> _inputLayout;
	shared_ptr<VertexShader> _vertexShader;
	shared_ptr<PixelShader> _pixelShader;
};
  • ResourceManager만이 생성 및 내부 데이터 접근이 가능하도록 friend로 지정.
  • InputLayout, VertexShader, PixelShader 세 가지 요소를 보유.

📌 8. 기본 셰이더 생성 함수

void ResourceManager::CreateDefaultShader()
{
	auto vertexShader = make_shared<VertexShader>(_device);
	vertexShader->Create(L"Default.hlsl", "VS", "vs_5_0");

	auto inputLayout = make_shared<InputLayout>(_device);
	inputLayout->Create(VertexTextureData::descs, vertexShader->GetBlob());

	auto pixelShader = make_shared<PixelShader>(_device);
	pixelShader->Create(L"Default.hlsl", "PS", "ps_5_0");

	auto shader = make_shared<Shader>();
	shader->SetName(L"Default");
	shader->_vertexShader = vertexShader;
	shader->_inputLayout = inputLayout;
	shader->_pixelShader = pixelShader;

	Add(shader->GetName(), shader);
}
  • Default.hlsl을 통해 정점/픽셀 셰이더 생성.
  • 셰이더를 이름 "Default"로 ResourceManager에 등록.

📌 9. Material 클래스 선언 및 정의

class Material : public ResourceBase
{
public:
	Material();
	virtual ~Material();

	auto GetShader();
	auto GetTexture();

	void SetShader(shared_ptr<Shader> shader);
	void SetTexture(shared_ptr<Texture> texture);

private:
	shared_ptr<Shader> _shader;
	shared_ptr<Texture> _texture;
};
  • Material은 시각적 속성을 담당하는 핵심 클래스입니다.
  • 내부적으로 ShaderTexture를 포함하며, 이후 조명, 애니메이션, 머티리얼 파라미터 등을 추가 확장할 수 있도록 설계되어 있습니다.

📌 10. 기본 Material 생성 함수

void ResourceManager::CreateDefaultMaterial()
{
	shared_ptr<Material> material = make_shared<Material>();
	material->SetName(L"Default");
	material->SetShader(Get<Shader>(L"Default"));
	material->SetTexture(Get<Texture>(L"chiikawa")); // 또는 "Cat", "Test"
	Add(material->GetName(), material);
}
  • "Default"라는 이름으로 Material을 생성하여 ResourceManager에 등록.
  • 내부 Shader는 "Default" 셰이더, Texture는 "chiikawa" 등을 사용함.

📌 11. MeshRenderer에서 Material 통합

shared_ptr<Material> _material;

void SetMaterial(shared_ptr<Material> material) { _material = material; }
void SetShader(shared_ptr<Shader> shader) { _material->SetShader(shader); }
void SetTexture(shared_ptr<Texture> texture) { _material->SetTexture(texture); }

auto GetMaterial() { return _material; }
auto GetVertexShader() { return GetMaterial()->GetShader()->GetVertexShader(); }
auto GetInputLayout() { return GetMaterial()->GetShader()->GetInputLayout(); }
auto GetPixelShader() { return GetMaterial()->GetShader()->GetPixelShader(); }
auto GetTexture() { return GetMaterial()->GetTexture(); }
  • MeshRenderer가 Material을 내부에 포함하고 있고, 외부에서 쉽게 Shader, Texture에 접근할 수 있도록 헬퍼 함수들을 제공함.
  • Renderer는 더 이상 Shader나 Texture를 직접 다루지 않고 Material 단위로 관리.

📌 12. SceneManager에서 Material 설정

auto material = RESOURCES->Get<Material>(L"Default");
meshRenderer->SetMaterial(material);
  • ResourceManager로부터 "Default" Material을 가져와서 MeshRenderer에 세팅.
  • Unity의 방식처럼, GameObject가 MeshRenderer를 통해 시각적 특성을 부여받는 구조를 구현.

📌 13. RenderManager에서 최종 렌더링 구조

info.inputLayout = meshRenderer->GetInputLayout();
info.vertexShader = meshRenderer->GetVertexShader();
info.pixelShader = meshRenderer->GetPixelShader();

_pipeline->SetVertexBuffer(meshRenderer->GetMesh()->GetVertexBuffer());
_pipeline->SetIndexBuffer(meshRenderer->GetMesh()->GetIndexBuffer());

_pipeline->SetTexture(0, SS_PixelShader, meshRenderer->GetTexture());
_pipeline->DrawIndexed(meshRenderer->GetMesh()->GetIndexBuffer()->GetCount(), 0, 0);
  • MeshRenderer의 헬퍼 함수들을 통해 필요한 모든 렌더링 요소(InputLayout, Shader, Texture 등)를 일괄 추출 가능.
  • RenderManager는 이를 기반으로 VertexBuffer, IndexBuffer 세팅 → Shader & Texture 바인딩 → Draw 호출까지 렌더링 전체를 담당.

✅ 핵심 요약

항목요약
Mesh 분리정점/인덱스 버퍼 → Mesh 클래스로 독립
Material 설계Shader + Texture 조합으로 재질 정의
Shader 구조VS, PS, InputLayout을 내부 구성 요소로 보유
ResourceManager모든 리소스를 이름 기반으로 중앙 관리
MeshRenderer 역할 변화Mesh + Material 보유, 렌더링 전용
RenderManager헬퍼 함수 기반으로 렌더링 요소 추출 및 처리
Unity 스타일 설계컴포넌트 기반 조립형 구조 완성
확장성 보장향후 Animation, Lighting, 파일 입출력 구조로 자연스럽게 확장 가능

profile
李家네_공부방

0개의 댓글