수업


✅ 주제

  • 이 강의는 Material(재질) 이란 개념을 구조화하고 클래스화하여,
    • Shader
    • Texture (Diffuse, Normal, Specular)
    • 조명 정보(MaterialDesc)
      를 한 번에 관리할 수 있는 렌더링 전용 리소스 시스템을 구현하는 것이 핵심이다.
  • 또한, Material을 공유 리소스로 활용하면서도, 오브젝트별로 속성을 다르게 적용하기 위해 Clone() 복제 방식을 도입한다.

📘 개념

  • Material은 Shader에 전달되는 인자의 모음이다.
    하나의 오브젝트가 어떤 텍스처, 어떤 쉐이더, 어떤 조명 반응을 가질지를 이 객체 하나로 통합한다.
  • 기존에는 MeshRenderer가 Shader나 Texture를 직접 가지고 있었지만,
    → 이제는 모두 Material이 관리한다.
  • Material은 공용 리소스이기 때문에, 하나를 수정하면 이를 사용하는 오브젝트 전체에 영향이 간다.
  • 따라서 오브젝트별로 독립적인 재질 표현을 원할 경우, 반드시 Clone() 함수를 통해 복제본을 생성해 사용해야 한다.

🧾 용어 정리

용어의미
MaterialShader, Texture, 조명 파라미터를 통합한 렌더링 리소스 객체
MaterialDescambient, diffuse, specular, emissive 등 조명 색상 정보를 담은 구조체
ShaderResourceVariable (SRV)쉐이더에서 Texture를 받아오기 위한 리소스 변수
Clone()Material 객체를 복제하여 원본과 독립된 설정이 가능한 새 Material을 생성
Update()Material 정보를 Shader에 전달해 GPU 렌더링에 반영하는 함수

🧠 코드 분석


📄 Material 클래스 정의 (Material.h)

class Material : public ResourceBase
{
public:
	shared_ptr<Shader> GetShader();
	MaterialDesc& GetMaterialDesc();
	shared_ptr<Texture> GetDiffuseMap();
	shared_ptr<Texture> GetNormalMap();
	shared_ptr<Texture> GetSpecularMap();

	void SetShader(shared_ptr<Shader> shader);
	void SetDiffuseMap(shared_ptr<Texture> diffuseMap);
	void SetNormalMap(shared_ptr<Texture> normalMap);
	void SetSpecularMap(shared_ptr<Texture> specularMap);

	void Update(); // Shader에 데이터 반영
	shared_ptr<Material> Clone(); // 복제 생성

private:
	MaterialDesc _desc;
	shared_ptr<Shader> _shader;
	shared_ptr<Texture> _diffuseMap;
	shared_ptr<Texture> _normalMap;
	shared_ptr<Texture> _specularMap;

	// Shader에서 각 맵과 연결될 SRV 변수 캐싱
	ComPtr<ID3DX11EffectShaderResourceVariable> _diffuseEffectBuffer;
	ComPtr<ID3DX11EffectShaderResourceVariable> _normalEffectBuffer;
	ComPtr<ID3DX11EffectShaderResourceVariable> _specularEffectBuffer;
};

📄 Material 클래스 구현 (Material.cpp)

SetShader()

void Material::SetShader(shared_ptr<Shader> shader)
{
	_shader = shader;
	_diffuseEffectBuffer = shader->GetSRV("DiffuseMap");
	_normalEffectBuffer = shader->GetSRV("NormalMap");
	_specularEffectBuffer = shader->GetSRV("SpecularMap");
}
  • Shader와 연동되는 변수(SRV)를 캐싱한다. 나중에 Update할 때 빠르게 바인딩하기 위함.

Update()

void Material::Update()
{
	if (_shader == nullptr) return;

	RENDER->PushMaterialData(_desc); // MaterialDesc 전달

	if (_diffuseMap)
		_diffuseEffectBuffer->SetResource(_diffuseMap->GetComPtr().Get());

	if (_normalMap)
		_normalEffectBuffer->SetResource(_normalMap->GetComPtr().Get());

	if (_specularMap)
		_specularEffectBuffer->SetResource(_specularMap->GetComPtr().Get());
}
  • Update 시 Shader에 조명 색상 정보 + 텍스처 바인딩이 모두 진행된다.

Clone()

shared_ptr<Material> Material::Clone()
{
	auto material = make_shared<Material>();

	material->_desc = _desc;
	material->_shader = _shader;
	material->_diffuseMap = _diffuseMap;
	material->_normalMap = _normalMap;
	material->_specularMap = _specularMap;

	material->_diffuseEffectBuffer = _diffuseEffectBuffer;
	material->_normalEffectBuffer = _normalEffectBuffer;
	material->_specularEffectBuffer = _specularEffectBuffer;

	return material;
}
  • Clone을 통해 원본과 동일한 속성을 갖지만, 수정 시 서로 영향을 주지 않는 새로운 Material을 생성한다.

📄 MeshRenderer 연동

MeshRenderer.h

shared_ptr<Material> _material;
void SetMaterial(shared_ptr<Material> material) { _material = material; }

MeshRenderer::Update()

void MeshRenderer::Update()
{
	if (_mesh == nullptr || _material == nullptr) return;

	auto shader = _material->GetShader();
	if (shader == nullptr) return;

	_material->Update(); // 모든 Material 관련 데이터 Shader에 적용

	auto world = GetTransform()->GetWorldMatrix();
	RENDER->PushTransformData(TransformDesc{ world });

	// Vertex/Index Buffer 바인딩 및 Draw
	...
	shader->DrawIndexed(...);
}

📄 Material 사용 예시 (MaterialDemo)

✅ Material 생성 및 리소스 등록

shared_ptr<Material> material = make_shared<Material>();
material->SetShader(_shader);

auto texture = RESOURCES->Load<Texture>(L"Veigar", L"..\\Resources\\Textures\\veigar.jpg");
material->SetDiffuseMap(texture);

MaterialDesc& desc = material->GetMaterialDesc();
desc.ambient = Vec4(1.f);
desc.diffuse = Vec4(1.f);

RESOURCES->Add(L"Veigar", material); // Resource 등록

✅ Material 적용

// Sphere
_obj->GetMeshRenderer()->SetMaterial(RESOURCES->Get<Material>(L"Veigar"));

// Cube (복제 후 다른 색상 적용)
auto material = RESOURCES->Get<Material>(L"Veigar")->Clone();
material->GetMaterialDesc().ambient = Vec4(0.f);
material->GetMaterialDesc().diffuse = Vec4(0.f);

_obj2->GetMeshRenderer()->SetMaterial(material);

✅ 핵심 정리

  • Material 클래스는 Shader, Texture, 색상 정보(MaterialDesc)를 통합 관리하는 핵심 구조이다.
  • Shader에 값을 넘겨줄 모든 정보를 이 클래스를 통해 일원화했다.
  • Material은 공유 리소스로 등록되기 때문에, 한 Material을 여러 오브젝트에서 재사용 가능하다.
  • 오브젝트별로 다른 조명 표현이 필요할 경우 Clone()으로 복제한 Material을 사용해야 한다.
  • MeshRenderer는 이제 Shader나 Texture를 직접 다루지 않고, Material을 통해 렌더링 정보를 일괄 처리한다.
  • 이 구조는 Unity, Unreal 등에서도 사용하는 표준적인 렌더링 파이프라인 구조이다.

✨ 다음 학습 주제 추천

  • NormalMap 적용 실습: Material의 _normalMap을 실제 조명 계산에 반영하는 고급 조명 효과
  • ImGui 연동: 실시간으로 MaterialDesc(ambient/diffuse 등)를 조절하는 실습
  • Material Editor 제작: 에디터에서 Shader/Texture/조명 속성을 시각적으로 수정하는 UI 도구 설계

원하시는 주제로 이어서 작성해드릴 수 있습니다. 언제든 말씀해주세요!좋습니다. 요청하신 내용대로 "Material" 강의 블로그 글을 기반으로 한 줄도 빠짐없이 완벽하게 분석하여, 실제 강의에서 바로 사용할 수 있는 완성형 학습 교재로 재작성해드렸습니다. 모든 개념, 용어, 코드 흐름, 핵심 정리까지 포함하였습니다.


🎓 Material 시스템 완전 구현 - 강의용 학습 교재


✅ 주제

  • 이 강의는 Material(재질) 이란 개념을 구조화하고 클래스화하여,
    • Shader
    • Texture (Diffuse, Normal, Specular)
    • 조명 정보(MaterialDesc)
      를 한 번에 관리할 수 있는 렌더링 전용 리소스 시스템을 구현하는 것이 핵심이다.
  • 또한, Material을 공유 리소스로 활용하면서도, 오브젝트별로 속성을 다르게 적용하기 위해 Clone() 복제 방식을 도입한다.

📘 개념

  • Material은 Shader에 전달되는 인자의 모음이다.
    하나의 오브젝트가 어떤 텍스처, 어떤 쉐이더, 어떤 조명 반응을 가질지를 이 객체 하나로 통합한다.
  • 기존에는 MeshRenderer가 Shader나 Texture를 직접 가지고 있었지만,
    → 이제는 모두 Material이 관리한다.
  • Material은 공용 리소스이기 때문에, 하나를 수정하면 이를 사용하는 오브젝트 전체에 영향이 간다.
  • 따라서 오브젝트별로 독립적인 재질 표현을 원할 경우, 반드시 Clone() 함수를 통해 복제본을 생성해 사용해야 한다.

🧾 용어 정리

용어의미
MaterialShader, Texture, 조명 파라미터를 통합한 렌더링 리소스 객체
MaterialDescambient, diffuse, specular, emissive 등 조명 색상 정보를 담은 구조체
ShaderResourceVariable (SRV)쉐이더에서 Texture를 받아오기 위한 리소스 변수
Clone()Material 객체를 복제하여 원본과 독립된 설정이 가능한 새 Material을 생성
Update()Material 정보를 Shader에 전달해 GPU 렌더링에 반영하는 함수

🧠 코드 분석


📄 Material 클래스 정의 (Material.h)

class Material : public ResourceBase
{
public:
	shared_ptr<Shader> GetShader();
	MaterialDesc& GetMaterialDesc();
	shared_ptr<Texture> GetDiffuseMap();
	shared_ptr<Texture> GetNormalMap();
	shared_ptr<Texture> GetSpecularMap();

	void SetShader(shared_ptr<Shader> shader);
	void SetDiffuseMap(shared_ptr<Texture> diffuseMap);
	void SetNormalMap(shared_ptr<Texture> normalMap);
	void SetSpecularMap(shared_ptr<Texture> specularMap);

	void Update(); // Shader에 데이터 반영
	shared_ptr<Material> Clone(); // 복제 생성

private:
	MaterialDesc _desc;
	shared_ptr<Shader> _shader;
	shared_ptr<Texture> _diffuseMap;
	shared_ptr<Texture> _normalMap;
	shared_ptr<Texture> _specularMap;

	// Shader에서 각 맵과 연결될 SRV 변수 캐싱
	ComPtr<ID3DX11EffectShaderResourceVariable> _diffuseEffectBuffer;
	ComPtr<ID3DX11EffectShaderResourceVariable> _normalEffectBuffer;
	ComPtr<ID3DX11EffectShaderResourceVariable> _specularEffectBuffer;
};

📄 Material 클래스 구현 (Material.cpp)

SetShader()

void Material::SetShader(shared_ptr<Shader> shader)
{
	_shader = shader;
	_diffuseEffectBuffer = shader->GetSRV("DiffuseMap");
	_normalEffectBuffer = shader->GetSRV("NormalMap");
	_specularEffectBuffer = shader->GetSRV("SpecularMap");
}
  • Shader와 연동되는 변수(SRV)를 캐싱한다. 나중에 Update할 때 빠르게 바인딩하기 위함.

Update()

void Material::Update()
{
	if (_shader == nullptr) return;

	RENDER->PushMaterialData(_desc); // MaterialDesc 전달

	if (_diffuseMap)
		_diffuseEffectBuffer->SetResource(_diffuseMap->GetComPtr().Get());

	if (_normalMap)
		_normalEffectBuffer->SetResource(_normalMap->GetComPtr().Get());

	if (_specularMap)
		_specularEffectBuffer->SetResource(_specularMap->GetComPtr().Get());
}
  • Update 시 Shader에 조명 색상 정보 + 텍스처 바인딩이 모두 진행된다.

Clone()

shared_ptr<Material> Material::Clone()
{
	auto material = make_shared<Material>();

	material->_desc = _desc;
	material->_shader = _shader;
	material->_diffuseMap = _diffuseMap;
	material->_normalMap = _normalMap;
	material->_specularMap = _specularMap;

	material->_diffuseEffectBuffer = _diffuseEffectBuffer;
	material->_normalEffectBuffer = _normalEffectBuffer;
	material->_specularEffectBuffer = _specularEffectBuffer;

	return material;
}
  • Clone을 통해 원본과 동일한 속성을 갖지만, 수정 시 서로 영향을 주지 않는 새로운 Material을 생성한다.

📄 MeshRenderer 연동

MeshRenderer.h

shared_ptr<Material> _material;
void SetMaterial(shared_ptr<Material> material) { _material = material; }

MeshRenderer::Update()

void MeshRenderer::Update()
{
	if (_mesh == nullptr || _material == nullptr) return;

	auto shader = _material->GetShader();
	if (shader == nullptr) return;

	_material->Update(); // 모든 Material 관련 데이터 Shader에 적용

	auto world = GetTransform()->GetWorldMatrix();
	RENDER->PushTransformData(TransformDesc{ world });

	// Vertex/Index Buffer 바인딩 및 Draw
	...
	shader->DrawIndexed(...);
}

📄 Material 사용 예시 (MaterialDemo)

✅ Material 생성 및 리소스 등록

shared_ptr<Material> material = make_shared<Material>();
material->SetShader(_shader);

auto texture = RESOURCES->Load<Texture>(L"Veigar", L"..\\Resources\\Textures\\veigar.jpg");
material->SetDiffuseMap(texture);

MaterialDesc& desc = material->GetMaterialDesc();
desc.ambient = Vec4(1.f);
desc.diffuse = Vec4(1.f);

RESOURCES->Add(L"Veigar", material); // Resource 등록

✅ Material 적용

// Sphere
_obj->GetMeshRenderer()->SetMaterial(RESOURCES->Get<Material>(L"Veigar"));

// Cube (복제 후 다른 색상 적용)
auto material = RESOURCES->Get<Material>(L"Veigar")->Clone();
material->GetMaterialDesc().ambient = Vec4(0.f);
material->GetMaterialDesc().diffuse = Vec4(0.f);

_obj2->GetMeshRenderer()->SetMaterial(material);

✅ 핵심

  • Material 클래스는 Shader, Texture, 색상 정보(MaterialDesc)를 통합 관리하는 핵심 구조이다.
  • Shader에 값을 넘겨줄 모든 정보를 이 클래스를 통해 일원화했다.
  • Material은 공유 리소스로 등록되기 때문에, 한 Material을 여러 오브젝트에서 재사용 가능하다.
  • 오브젝트별로 다른 조명 표현이 필요할 경우 Clone()으로 복제한 Material을 사용해야 한다.
  • MeshRenderer는 이제 Shader나 Texture를 직접 다루지 않고, Material을 통해 렌더링 정보를 일괄 처리한다.
  • 이 구조는 Unity, Unreal 등에서도 사용하는 표준적인 렌더링 파이프라인 구조이다.

profile
李家네_공부방

0개의 댓글