Material
- 3D그래픽에서
Mesh의 표면이 어떻게 보일지를 결정하는 데이터 집합
- 물체의 빛에 대한 정보와
Texture정보를 가지고 있음
Clone() : A, B 물체가 하나의 Material을 가지고 있을때 B의 Material을 수정하면 A의 Material도 같으 수정되는 현상을 막기 위해 사용되는 함수, 서로 다른 Material을 사용하면 되지만 같은 Material에서 수정할 경우에 사용
Material.h
#pragma once
#include "ResourceBase.h"
class Material : public ResourceBase
{
using Super = ResourceBase;
public:
Material();
virtual ~Material();
shared_ptr<Shader> GetShader() { return _shader; }
MaterialDesc& GetMaterialDesc() { return _desc; }
shared_ptr<Texture> GetDiffuseMap() { return _diffuseMap; }
shared_ptr<Texture> GetNormalMap() { return _normalMap; }
shared_ptr<Texture> GetSpecularMap() { return _specularMap; }
void SetShader(shared_ptr<Shader> shader);
void SetDiffuseMap(shared_ptr<Texture> diffuseMap) { _diffuseMap = diffuseMap; }
void SetNormalMap(shared_ptr<Texture> normalMap) { _normalMap = normalMap; }
void SetSpecularMap(shared_ptr<Texture> specularMap) { _specularMap = specularMap; }
void Update();
shared_ptr<Material> Clone();
private:
friend class MeshRenderer;
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.cpp
#include "pch.h"
#include "Material.h"
Material::Material() : Super(ResourceType::Material)
{
}
Material::~Material()
{
}
void Material::SetShader(shared_ptr<Shader> shader)
{
_shader = shader;
_diffuseEffectBuffer = shader->GetSRV("DiffuseMap");
_normalEffectBuffer = shader->GetSRV("NormalMap");
_specularEffectBuffer = shader->GetSRV("SpecularMap");
}
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());
}
shared_ptr<Material> Material::Clone()
{
shared_ptr<Material> 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;
}
MeshRenderer.h
MeshRenderer에서 가지고 있던 Texture와 Shader를 Material로 변경
Update()에서 Material에서 Shader를 가져오고 Material->Update()형식으로 변경
#pragma once
#include "Component.h"
#include "Material.h"
class Mesh;
class Shader;
class Material;
class MeshRenderer : public Component
{
using Super = Component;
public:
MeshRenderer();
virtual ~MeshRenderer();
virtual void Update() override;
void SetMesh(shared_ptr<Mesh> mesh) { _mesh = mesh; }
void SetMaterial(shared_ptr<Material> material) { _material = material; }
private:
shared_ptr<Mesh> _mesh;
shared_ptr<Material> _material;
};
MeshRenderer.cpp
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 });
uint32 stride = _mesh->GetVertexBuffer()->GetStride();
uint32 offset = _mesh->GetVertexBuffer()->GetOffset();
DC->IASetVertexBuffers(0, 1, _mesh->GetVertexBuffer()->GetComPtr().GetAddressOf(), &stride, &offset);
DC->IASetIndexBuffer(_mesh->GetIndexBuffer()->GetComPtr().Get(), DXGI_FORMAT_R32_UINT, 0);
shader->DrawIndexed(0, 0, _mesh->GetIndexBuffer()->GetCount(), 0, 0);
}
17. MaterialDemo.cpp
Init()초반에서 Material생성 및 초기화
ResourceManager를 통해서 리소스 추가
- obj2에서
Material을 Clone()으로 만들어서 하나가 수정될 때 두개가 같이 수정되는 문제 방지
void MaterialDemo::Init()
{
RESOURCES->Init();
_shader = make_shared<Shader>(L"13.Lighting.fx");
{
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);
}
_camera = make_shared<GameObject>();
_camera->GetOrAddTransform()->SetPosition(Vec3{ 0.f, 0.f, -10.f });
_camera->AddComponent(make_shared<Camera>());
_camera->AddComponent(make_shared<CameraScript>());
_obj = make_shared<GameObject>();
_obj->GetOrAddTransform();
_obj->AddComponent(make_shared<MeshRenderer>());
{
auto mesh = RESOURCES->Get<Mesh>(L"Sphere");
_obj->GetMeshRenderer()->SetMesh(mesh);
}
{
auto material = RESOURCES->Get<Material>(L"Veigar");
_obj->GetMeshRenderer()->SetMaterial(material);
}
_obj2 = make_shared<GameObject>();
_obj2->GetOrAddTransform()->SetPosition(Vec3{ 0.5f, 0.f, 2.f });
_obj2->AddComponent(make_shared<MeshRenderer>());
{
auto mesh = RESOURCES->Get<Mesh>(L"Cube");
_obj2->GetMeshRenderer()->SetMesh(mesh);
}
{
auto material = RESOURCES->Get<Material>(L"Veigar")->Clone();
MaterialDesc& desc = material->GetMaterialDesc();
desc.ambient = Vec4(0.f);
desc.diffuse = Vec4(0.f);
_obj2->GetMeshRenderer()->SetMaterial(material);
}
RENDER->Init(_shader);
}
결과
- obj2의
ambient와 diffuse가 각 0으로 설정되어 있어 큐브는 안보임

참고 강의
https://www.inflearn.com/courses/lecture?courseId=329791&type=LECTURE&unitId=161134&tab=curriculum&subtitleLanguage=ko