수업
✅ 주제
- 이 강의는 Material(재질) 이란 개념을 구조화하고 클래스화하여,
- Shader
- Texture (Diffuse, Normal, Specular)
- 조명 정보(MaterialDesc)
 를 한 번에 관리할 수 있는 렌더링 전용 리소스 시스템을 구현하는 것이 핵심이다.
 
- 또한, Material을 공유 리소스로 활용하면서도, 오브젝트별로 속성을 다르게 적용하기 위해 Clone() 복제 방식을 도입한다.
📘 개념
- Material은 Shader에 전달되는 인자의 모음이다.
 하나의 오브젝트가 어떤 텍스처, 어떤 쉐이더, 어떤 조명 반응을 가질지를 이 객체 하나로 통합한다.
- 기존에는 MeshRenderer가 Shader나 Texture를 직접 가지고 있었지만,
 → 이제는 모두 Material이 관리한다.
- Material은 공용 리소스이기 때문에, 하나를 수정하면 이를 사용하는 오브젝트 전체에 영향이 간다.
- 따라서 오브젝트별로 독립적인 재질 표현을 원할 경우, 반드시 Clone() 함수를 통해 복제본을 생성해 사용해야 한다.
🧾 용어 정리
| 용어 | 의미 | 
|---|
| Material | Shader, Texture, 조명 파라미터를 통합한 렌더링 리소스 객체 | 
| MaterialDesc | ambient, 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(); 
	shared_ptr<Material> Clone(); 
private:
	MaterialDesc _desc;
	shared_ptr<Shader> _shader;
	shared_ptr<Texture> _diffuseMap;
	shared_ptr<Texture> _normalMap;
	shared_ptr<Texture> _specularMap;
	
	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); 
	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(); 
	auto world = GetTransform()->GetWorldMatrix();
	RENDER->PushTransformData(TransformDesc{ world });
	
	...
	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); 
✅ Material 적용
_obj->GetMeshRenderer()->SetMaterial(RESOURCES->Get<Material>(L"Veigar"));
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() 함수를 통해 복제본을 생성해 사용해야 한다.
🧾 용어 정리
| 용어 | 의미 | 
|---|
| Material | Shader, Texture, 조명 파라미터를 통합한 렌더링 리소스 객체 | 
| MaterialDesc | ambient, 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(); 
	shared_ptr<Material> Clone(); 
private:
	MaterialDesc _desc;
	shared_ptr<Shader> _shader;
	shared_ptr<Texture> _diffuseMap;
	shared_ptr<Texture> _normalMap;
	shared_ptr<Texture> _specularMap;
	
	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); 
	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(); 
	auto world = GetTransform()->GetWorldMatrix();
	RENDER->PushTransformData(TransformDesc{ world });
	
	...
	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); 
✅ Material 적용
_obj->GetMeshRenderer()->SetMaterial(RESOURCES->Get<Material>(L"Veigar"));
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 등에서도 사용하는 표준적인 렌더링 파이프라인 구조이다.