# MeshRenderer

{% embed url="<https://youtu.be/x00YggGkyag>" %}

## <mark style="background-color:yellow;">MeshRenderer의 역할과 구조</mark>

MeshRenderer는 3D 게임 오브젝트를 렌더링하기 위한 핵심 컴포넌트입니다. Component 클래스를 상속받아 구현되었으며, 다음과 같은 주요 기능을 담당합니다:

1. 3D 모델의 형태(Mesh)와 재질(Material) 정보 관리
2. 렌더링 파이프라인 설정
3. 렌더링 패스(RenderPass) 관리

```
class MeshRenderer : public Component
{
private:
    // Mesh
    shared_ptr<Mesh> _mesh;
    shared_ptr<Material> _material;
    shared_ptr<Model> _model;

    RasterizerStateInfo _rasterzerStates;
    vector<shared_ptr<RenderPass>> _renderPasses;
    bool _isUseEnvironmentMap = false;
};
```

## <mark style="background-color:yellow;">Mesh 클래스</mark>

* **Mesh 클래스는 3D 객체의 형태 데이터를 저장하고 관리합니다.**
  * 주요 구성 요소

```
class Mesh : public ResourceBase
{
public:
    void CreateQuad_NormalTangent();
    void CreateGrid_NormalTangent(int32 sizeX, int32 sizeZ);
    void CreateCube_NormalTangent();
    void CreateSphere_NormalTangent();
    void CreateCylinder_NormalTangent();
private:
    shared_ptr<Geometry<VertexTextureNormalTangentBlendData>> _geometry;
    shared_ptr<Geometry<VertexTerrain>> _geometryForTerrain;
    shared_ptr<Buffer> _buffer;
    // 추가 지형 관련 데이터...
};
```

### <mark style="background-color:blue;">Geometry 클래스 - 정점 데이터 관리의 핵심</mark>

* **Geometry 클래스는 템플릿을 사용하여 다양한 정점 타입을 지원하는 유연한 구조로 설계되었습니다:**

```
template <typename T>
class Geometry
{
public:
    Geometry() {}
    ~Geometry() {}

    void SetVertices(const vector<T>& vertices) { _vertices = vertices; }
    void SetIndices(const vector<uint32>& indices) { _indices = indices; }
    void AddVertex(const T& vertex) { _vertices.push_back(vertex); }
    void AddVertices(const vector<T>& vertices) { _vertices.insert(_vertices.end(), vertices.begin(), vertices.end()); }

    void AddIndex(uint32 index) { _indices.push_back(index); }
    void AddIndices(const vector<uint32>& indices) { _indices.insert(_indices.end(), indices.begin(), indices.end()); }
    vector<T>& GetVertices() { return _vertices; }
    vector<uint32>& GetIndices() { return _indices; }
private:
    vector<T> _vertices;
    vector<uint32> _indices;
};
```

* **이 템플릿 구현의 핵심 특징:**

1. 타입 독립성: 템플릿 T를 통해 어떤 정점 구조체도 저장 가능
2. 데이터 추가 방식:
   1. 단일 정점/인덱스 추가 (AddVertex, AddIndex)
   2. 벡터로 일괄 추가 (AddVertices, AddIndices)
   3. 전체 설정 (SetVertices, SetIndices)
3. 벡터 기반 저장: 동적으로 크기가 변할 수 있는 메시 데이터 처리에 적합

* **다양한 정점 구조체 타입**
  * Mesh 클래스에서는 Geometry 템플릿을 다양한 정점 타입으로 인스턴스화하여 사용합니다:

```
shared_ptr<Geometry<VertexTextureNormalTangentBlendData>> _geometry;
shared_ptr<Geometry<VertexTerrain>> _geometryForTerrain;
```

* **주요 정점 구조체 타입 및 용도:**

```
struct VertexTextureData
{
	Vec3 position = { 0.f, 0.f, 0.f };
	Vec2 uv = { 0.f, 0.f };

	static vector<D3D11_INPUT_ELEMENT_DESC> descs;
};
struct VertexTextureNormalData
{
	Vec3 position = { 0.f, 0.f, 0.f };
	Vec2 uv = { 0.f, 0.f };
	Vec3 normal = { 0.f, 0.f, 0.f };
	VertexTextureNormalData() {};
	VertexTextureNormalData(const Vec3& pos, const Vec2& texCoord, const Vec3& norm)
		: position(pos), uv(texCoord), normal(norm) {}
	static vector<D3D11_INPUT_ELEMENT_DESC> descs;
};

struct VertexTextureNormalTangentData
{
	Vec3 position = { 0, 0, 0 };
	Vec2 uv = { 0, 0 };
	Vec3 normal = { 0, 0, 0 };
	Vec3 tangent = { 0, 0, 0 };
	VertexTextureNormalTangentData() {};
	VertexTextureNormalTangentData(const Vec3& pos, const Vec2& texCoord, const Vec3& norm, const Vec3& tan)
		: position(pos), uv(texCoord), normal(norm), tangent(tan) {}
	static vector<D3D11_INPUT_ELEMENT_DESC> descs;
};
struct VertexTerrain
{
	Vec3 position;
	Vec2 uv;
	Vec2 BoundsY;
	static vector<D3D11_INPUT_ELEMENT_DESC> descs;
};

struct VertexParticle
{
	Vec3 position;
	Vec3 velocity;
	Vec2 size;
	float age;
	uint32 type;
	static vector<D3D11_INPUT_ELEMENT_DESC> descs;
};
```

* **Geometry를 활용한 메시 생성 과정**
  * 예를 들어, 구(Sphere) 메시를 생성하는 과정을 살펴보겠습니다:

```
void Mesh::CreateSphere_NormalTangent()
{
    _geometry = make_shared<Geometry<VertexTextureNormalTangentBlendData>>();

    float radius = 0.5f;
    uint32 stackCount = 20;
    uint32 sliceCount = 20;

    vector<VertexTextureNormalTangentBlendData> vertices;
    vector<uint32> indices;

    // 북극점 정점
    VertexTextureNormalTangentBlendData v;
    v.position = Vec3(0.0f, radius, 0.0f);
    v.uv = Vec2(0.5f, 0.0f);
    v.normal = v.position;
    v.normal.Normalize();
    v.tangent = Vec3(1.0f, 0.0f, 0.0f);
    vertices.push_back(v);

    // 구의 각 층(stack)과 조각(slice)마다 정점 생성
    float stackAngle = XM_PI / stackCount;
    float sliceAngle = XM_2PI / sliceCount;

    float deltaU = 1.f / static_cast<float>(sliceCount);
    float deltaV = 1.f / static_cast<float>(stackCount);

    // 정점 생성 로직...
    // 인덱스 생성 로직...

    // Geometry에 정점과 인덱스 데이터 설정
    _geometry->SetVertices(vertices);
    _geometry->SetIndices(indices);

    // Buffer 생성
    _buffer = make_shared<Buffer>();
    _buffer->CreateBuffer(BufferType::VERTEX_BUFFER, vertices, 0, false, false);
    _buffer->CreateBuffer(BufferType::INDEX_BUFFER, indices, 0, false, false);
}
```

이 과정에서 Geometry는:

1. 구의 모든 정점과 인덱스 데이터를 저장
2. 데이터를 Buffer 클래스에 전달하여 GPU 메모리에 업로드할 준비

### <mark style="background-color:blue;">Buffer 클래스 - GPU 메모리 관리의 핵심</mark>

* #### Buffer 클래스 구조와 역할
  * Buffer 클래스는 CPU 메모리의 데이터를 GPU 메모리로 전송하고 관리하는 역할을 담당합니다:

```
class Buffer
{
public:
    Buffer();
    ~Buffer();

    template <typename T>
    void CreateBuffer(BufferType type, vector<T> source, uint32 slot = 0, bool cpuWrite = false, bool gpuWrite = false);

    template <typename T>
    void CreateConstantBuffer();

    template <typename T>
    void CopyData(const T& data);

    uint32 GetStride() { return _stride; }
    uint32 GetOffset() { return _offset; }
    uint32 GetSlot() { return _slot; }

    ComPtr<ID3D11Buffer> GetVertexBuffer() { return _vertexBuffer; }
    ComPtr<ID3D11Buffer> GetIndexBuffer() { return _indexBuffer; }
    ComPtr<ID3D11Buffer> GetConstantBuffer() { return _constantBuffer; }
    
private:
    ComPtr<ID3D11Buffer> _vertexBuffer;
    ComPtr<ID3D11Buffer> _indexBuffer;
    ComPtr<ID3D11Buffer> _constantBuffer = nullptr;
    uint32 _stride = 0;
    uint32 _offset = 0;
    uint32 _slot = 0;
};
```

* **버퍼 생성 매커니즘**
  * 가장 핵심적인 메서드인 CreateBuffer 템플릿 함수를 자세히 살펴보겠습니다:

```
template <typename T>
void Buffer::CreateBuffer(BufferType type, vector<T> source, uint32 slot = 0, bool cpuWrite = false, bool gpuWrite = false)
{
    _slot = slot;

    if (type == BufferType::VERTEX_BUFFER)
    {
        _stride = sizeof(T);
        D3D11_BUFFER_DESC desc;
        ZeroMemory(&desc, sizeof(desc));
        desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
        desc.ByteWidth = (uint32)(sizeof(T) * static_cast<uint32>(source.size()));

        // CPU/GPU 접근 권한에 따른 Usage 설정
        if (cpuWrite == false && gpuWrite == false)
        {
            desc.Usage = D3D11_USAGE_IMMUTABLE; // CPU Read, GPU Read
        }
        else if (cpuWrite == true && gpuWrite == false)
        {
            desc.Usage = D3D11_USAGE_DYNAMIC; // CPU Write, GPU Read
            desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
        }
        else if (cpuWrite == false && gpuWrite == true) // CPU Read, GPU Write
        {
            desc.Usage = D3D11_USAGE_DEFAULT;
        }
        else
        {
            desc.Usage = D3D11_USAGE_STAGING;
            desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
        }

        D3D11_SUBRESOURCE_DATA data;
        ZeroMemory(&data, sizeof(data));
        data.pSysMem = source.data();

        HRESULT hr = Graphics::GetInstance().GetDevice()->CreateBuffer(&desc, &data, _vertexBuffer.GetAddressOf());
        CHECK(hr);
    }
    else if (type == BufferType::INDEX_BUFFER)
    {
        // 인덱스 버퍼 생성 로직...
    }
}
```

* **CPU/GPU 메모리 접근 제어 시스템**
  * Buffer 클래스에서 가장 중요한 특징 중 하나는 CPU와 GPU 간의 메모리 접근 권한을 세밀하게 제어하는 기능입니다:
    * D3D11\_USAGE\_IMMUTABLE (cpuWrite=false, gpuWrite=false):
      1. 생성 후 변경 불가능한 버퍼
      2. CPU에서 초기화 후 GPU에서 읽기만 가능
    * D3D11\_USAGE\_DYNAMIC (cpuWrite=true, gpuWrite=false):
      1. CPU에서 자주 업데이트하는 버퍼
      2. GPU는 읽기만 가능
    * D3D11\_USAGE\_DEFAULT (cpuWrite=false, gpuWrite=true):
      1. GPU에서 쓰기 가능
      2. 주로 GPU-GPU 복사 작업에 사용
    * D3D11\_USAGE\_STAGING (cpuWrite=true, gpuWrite=true):
      1. CPU-GPU 간 데이터 전송에 사용

* **상수버퍼 관리**

```
template <typename T>
void Buffer::CreateConstantBuffer()
{
    D3D11_BUFFER_DESC desc;
    ZeroMemory(&desc, sizeof(desc));
    desc.Usage = D3D11_USAGE_DYNAMIC;
    desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    desc.ByteWidth = sizeof(T);
    desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

    HRESULT hr = Graphics::GetInstance().GetDevice()->CreateBuffer(&desc, nullptr, _constantBuffer.GetAddressOf());
    CHECK(hr);
}

template <typename T>
void Buffer::CopyData(const T& data)
{
    D3D11_MAPPED_SUBRESOURCE subResource;
    ZeroMemory(&subResource, sizeof(subResource));

    Graphics::GetInstance().GetDeviceContext()->Map(_constantBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
    ::memcpy(subResource.pData, &data, sizeof(data));
    Graphics::GetInstance().GetDeviceContext()->Unmap(_constantBuffer.Get(), 0);
}
```

위 방식으로 생성된 상수 버퍼는 다음과 같은 데이터를 GPU에 전달하는데 사용됩니다:

* 변환 행렬 (월드, 뷰, 투영)
* 재질 속성 (ambient, diffuse, specular)
* 조명 데이터
* 애니메이션 키프레임 정보
* 카메라 정보

## <mark style="background-color:yellow;">Material 클래스 - 텍스처와 셰이더 관리</mark>

* **Material 클래스는 3D 객체의 시각적 특성을 정의하고 관리하는 핵심 리소스입니다. 이 클래스는 객체가 빛을 어떻게 반사하고, 어떤 표면 질감을 가지며, 어떤 시각적 효과를 적용할지 결정합니다.**

```
class Material : public ResourceBase
{
private:
    // 셰이더와 텍스처 참조
    shared_ptr<Shader> _shader;
    shared_ptr<Texture> _texture;
    shared_ptr<Texture> _normalMap;
    shared_ptr<Texture> _diffuseMap;
    shared_ptr<Texture> _specularMap;
    
    // 재질 속성 관리
    shared_ptr<Buffer> _materialBuffer;
    MaterialDesc _materialDesc;
    
    // 환경 매핑과 큐브맵 관련
    ComPtr<ID3D11ShaderResourceView> _cubeMapSRV;
    wstring _materialName = L"None";
};
```

Material 클래스는 다음과 같은 핵심 요소들을 관리합니다:

1. 셰이더 참조: 객체를 어떻게 렌더링할지 결정하는 셰이더 프로그램
2. 텍스처 컬렉션: 객체의 표면 질감을 정의하는 다양한 텍스처 맵
3. 재질 속성: 주변광(ambient), 확산광(diffuse), 반사광(specular) 등 재질의 광학적 특성
4. 상수 버퍼: 이러한 속성을 셰이더에 전달하기 위한 버퍼

* **Material 클래스의 주요 메서드들:**

```
// 셰이더 및 텍스처 설정
void SetShader(shared_ptr<Shader> shader) { _shader = shader; }
void SetTexture(shared_ptr<Texture> texture) { _texture = texture; }
void SetNormalMap(shared_ptr<Texture> normal) { _normalMap = normal; }
void SetDiffuseMap(shared_ptr<Texture> diffuse) { _diffuseMap = diffuse; }
void SetSpecularMap(shared_ptr<Texture> specular) { _specularMap = specular; }

// 재질 속성 설정 및 GPU 전송
void SetMaterialDesc(MaterialDesc materialDesc) { _materialDesc = materialDesc; }
void PushMaterialDesc(); // 상수 버퍼를 통해 재질 속성을 GPU에 전송

// 특수 텍스처 생성
void CreateCubeMapTexture(shared_ptr<Texture> textureArray[6]);
void CreateEnvironmentMapTexture(shared_ptr<GameObject> gameObject);
```

Material 객체는 렌더링 과정에서 셰이더와 텍스처를 바인딩하고, 재질 속성을 상수 버퍼를 통해 GPU에 전달합니다. 이 과정에서 PushMaterialDesc() 메서드가 핵심 역할을 합니다:

```
void Material::PushMaterialDesc()
{
    // 아직 상수 버퍼가 없다면 생성
    if (_materialBuffer == nullptr)
    {
        _materialBuffer = make_shared<Buffer>();
        _materialBuffer->CreateConstantBuffer<MaterialDesc>();
    }
    
    // 최신 재질 속성을 상수 버퍼에 복사
    _materialBuffer->CopyData(_materialDesc);
}
```

### <mark style="background-color:blue;">Texture 클래스 - 시각적 이미지 데이터 관리</mark>

* **Material이 참조하는 Texture 클래스는 이미지 데이터를 로드하고 GPU에서 사용할 수 있는 형태로 관리합니다.**

```
class Texture : public ResourceBase
{
private:
    // DirectX 텍스처 리소스와 뷰
    ComPtr<ID3D11Texture2D> _texture;
    ComPtr<ID3D11ShaderResourceView> _srv;
    
    // 텍스처 메타데이터
    D3D11_TEXTURE2D_DESC _desc;
    ScratchImage _image;
};
```

Texture 클래스의 주요 기능:

1. 이미지 로딩: 다양한 형식(PNG, JPG, DDS 등)의 이미지 파일 로드
2. 리소스 뷰 생성: 셰이더에서 접근할 수 있는 ShaderResourceView 생성
3. 텍스처 속성 관리: 크기, 형식, 밉맵 레벨 등 설정

```
// 텍스처 로딩 및 생성
void Load(const wstring& path);
void Create(DXGI_FORMAT format, uint32 width, uint32 height, uint32 bindFlag);
void CreateFromTexture(ComPtr<ID3D11Texture2D> texture);

// 텍스처 정보 접근
ComPtr<ID3D11ShaderResourceView> GetShaderResourceView() { return _srv; }
ComPtr<ID3D11Texture2D> GetTexture() { return _texture; }
```

* **텍스처 로딩 과정의 예:**

```
void Texture::CreateTexture(const wstring& path)
{
	// 파일 확장자 얻기
	wstring ext = fs::path(path).extension();

	if (ext == L".dds" || ext == L".DDS")
	{
		LoadTextureFromDDS(path);
		return;
	}

	DirectX::TexMetadata md;
	DirectX::ScratchImage img;
	HRESULT hr = ::LoadFromWICFile(path.c_str(), WIC_FLAGS_FORCE_RGB, &md, img);
	CHECK(hr);

	// Generate Mipmaps
	DirectX::ScratchImage mipChain;
	hr = DirectX::GenerateMipMaps(
		img.GetImages(), img.GetImageCount(), img.GetMetadata(),
		DirectX::TEX_FILTER_DEFAULT, 0, mipChain);
	CHECK(hr);

	// Create shader resource view with mipmaps
	hr = ::CreateShaderResourceView(DEVICE.Get(),
		mipChain.GetImages(),
		mipChain.GetImageCount(),
		mipChain.GetMetadata(),
		_shaderResourceView.GetAddressOf());
	CHECK(hr);

	// 텍스처 포맷 확인
	DXGI_FORMAT format = md.format;

	_size.x = md.width;
	_size.y = md.height;
}

ComPtr<ID3D11ShaderResourceView> Texture::LoadTextureFromDDS(const wstring& path)
{
	// 파일 확장자 얻기
	wstring ext = fs::path(path).extension();

	DirectX::TexMetadata md;
	DirectX::ScratchImage img;

	HRESULT hr;

	if (ext == L".dds" || ext == L".DDS")
		hr = ::LoadFromDDSFile(path.c_str(), DDS_FLAGS_NONE, &md, img);
	else if (ext == L".tga" || ext == L".TGA")
		hr = ::LoadFromTGAFile(path.c_str(), &md, img);
	else // png, jpg, jpeg, bmp
		hr = ::LoadFromWICFile(path.c_str(), WIC_FLAGS_NONE, &md, img);

	CHECK(hr);

	hr = ::CreateShaderResourceView(DEVICE.Get(), img.GetImages(), img.GetImageCount(), md, _shaderResourceView.GetAddressOf());
	
	_size.x = md.width;
	_size.y = md.height;

	CHECK(hr);

	return _shaderResourceView;
}
```

Material 클래스는 여러 Texture 객체를 참조하며, 각 텍스처는 다른 시각적 속성(base color, normal map, specular map 등)을 담당합니다. 이 텍스처들은 셰이더에 바인딩되어 최종 렌더링 결과에 영향을 줍니다.

### <mark style="background-color:blue;">Shader 클래스 - GPU 프로그래밍 인터페이스</mark>

* **Material이 참조하는 또 다른 핵심 구성요소인 Shader 클래스는 GPU에서 실행되는 프로그램을 관리합니다**

```
class Shader : public ResourceBase
{
private:
    // 다양한 셰이더 타입
    ComPtr<ID3D11VertexShader> _vertexShader;    // 정점 처리
    ComPtr<ID3D11PixelShader> _pixelShader;      // 픽셀 처리
    ComPtr<ID3D11GeometryShader> _geometryShader; // 기하 처리
    ComPtr<ID3D11HullShader> _hullShader;        // 테셀레이션 제어
    ComPtr<ID3D11DomainShader> _domainShader;    // 테셀레이션 평가
    ComPtr<ID3D11ComputeShader> _computeShader;  // 범용 계산
    
    // 셰이더 바이트코드
    ComPtr<ID3DBlob> _vsBlob, _psBlob, _gsBlob, _hsBlob, _dsBlob, _csBlob;
    
    // 입력 레이아웃 및 셰이더 슬롯
    shared_ptr<InputLayout> _inputLayout;
    shared_ptr<ShaderSlot> _shaderSlot;
};
```

Shader 클래스의 주요 기능:

1. 셰이더 로딩 및 컴파일: HLSL 파일에서 셰이더 코드 로드 및 컴파일
2. DirectX 셰이더 객체 생성: 컴파일된 셰이더로 DirectX 셰이더 객체 생성
3. 리소스 바인딩 관리: 상수 버퍼, 텍스처 등 리소스를 셰이더에 바인딩

* **셰이더 로딩과 컴파일 과정:**

```
void Shader::LoadShaderFromFile(const wstring& path, const string& name, const string& version, ComPtr<ID3DBlob>& blob)
{
  ComPtr<ID3DBlob> errorBlob;

  const uint32 compileFlag = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;

  HRESULT hr = ::D3DCompileFromFile(
                path.c_str(),
		nullptr,
		D3D_COMPILE_STANDARD_FILE_INCLUDE,
		name.c_str(),
		version.c_str(),
		compileFlag,
		0,
		blob.GetAddressOf(),
		&errorBlob);

	
  if (FAILED(hr)) {
    if (errorBlob) {
      // 에러 메시지를 받아오고, OutputDebugStringA를 사용해 디버그 출력
      std::string errorMessage(static_cast<char*>(errorBlob->GetBufferPointer()), errorBlob->GetBufferSize());
      OutputDebugStringA(errorMessage.c_str()); // 디버그 콘솔로 메시지 출력
    }
    CHECK(hr); // 에러 체크 (예: 프로그램 종료 또는 에러 처리)
  }
}

void Shader::CreateShader(ShaderType type, const wstring& shaderPath, InputLayoutType inputType)
{
    // 셰이더 타입에 따라 다른 처리
    switch (type)
    {
    case ShaderType::VERTEX_SHADER:
        LoadShaderFromFile(shaderPath, "VS_Main", "vs_5_0", _vsBlob);
        DEVICE->CreateVertexShader(_vsBlob->GetBufferPointer(), _vsBlob->GetBufferSize(), nullptr, _vertexShader.GetAddressOf());
        
        // 입력 레이아웃 생성
        _inputLayout = make_shared<InputLayout>();
        _inputLayout->CreateInputLayout(inputType, _vsBlob);
        break;
        
    case ShaderType::PIXEL_SHADER:
        LoadShaderFromFile(shaderPath, "PS_Main", "ps_5_0", _psBlob);
        DEVICE->CreatePixelShader(_psBlob->GetBufferPointer(), _psBlob->GetBufferSize(), nullptr, _pixelShader.GetAddressOf());
        break;
        
    // 다른 셰이더 타입에 대한 처리...
    }
    
    // 셰이더 슬롯 초기화
    _shaderSlot = make_shared<ShaderSlot>();
}
```

리소스 바인딩 메서드는 셰이더 슬롯을 사용하여 상수 버퍼나 텍스처를 셰이더의 특정 레지스터에 바인딩합니다:

```
void Shader::PushConstantBufferToShader(ShaderType type, const wstring& name, UINT numBuffers, shared_ptr<Buffer> buffer)
{
    // 셰이더 슬롯에서 해당 이름의 레지스터 번호 조회
    int slot = _shaderSlot->GetSlotNumber(name);
    if (slot == -1)
    {
        slot = _shaderSlot->GetMaxSlotNumber() + 1;
        _shaderSlot->SetSlot(name, slot);
    }
    
    // 셰이더 타입에 따라 적절한 바인딩 함수 호출
    switch (type)
    {
    case ShaderType::VERTEX_SHADER:
        CONTEXT->VSSetConstantBuffers(slot, numBuffers, buffer->GetConstantBuffer().GetAddressOf());
        break;
    case ShaderType::PIXEL_SHADER:
        CONTEXT->PSSetConstantBuffers(slot, numBuffers, buffer->GetConstantBuffer().GetAddressOf());
        break;
    // 다른 셰이더 타입에 대한 처리...
    }
}
```

Material 클래스는 Shader 객체를 설정하고 이를 통해 상수 버퍼와 텍스처를 셰이더에 바인딩합니다. 이 과정에서 셰이더 슬롯이 중요한 역할을 합니다.

### <mark style="background-color:blue;">ShaderSlot 클래스 - 셰이더 리소스 바인딩 관리</mark>

* **ShaderSlot 클래스는 셰이더 리소스(상수 버퍼, 텍스처 등)가 어떤 레지스터 슬롯에 바인딩될지 관리합니다.**

```
class ShaderSlot
{
private:
    // 리소스 이름과 슬롯 번호의 매핑을 관리하는 맵
    vector<map<wstring, int>> slots;
    int maxSlotNumber = -1;

public:
    // 슬롯 설정 및 조회
    void SetSlot(wstring name, int slot);
    int GetSlotNumber(wstring name);
    int GetMaxSlotNumber() { return maxSlotNumber; }
};
```

* **셰이더 슬롯의 작동 방식:**

1. 셰이더 코드에서는 레지스터 바인딩을 통해 리소스에 접근합니다:

```
   // HLSL 셰이더 코드
   cbuffer TransformBuffer : register(b0)
   {
       matrix World;
       matrix View;
       matrix Projection;
   }
   
   Texture2D DiffuseMap : register(t0);
```

2. ShaderSlot 클래스는 이러한 리소스 이름(예: "TransformBuffer", "DiffuseMap")과 레지스터 슬롯(예: b0, t0)의 매핑을 관리합니다:

<pre><code>   void ShaderSlot::SetSlot(wstring name, int slot)
   {
       for (int i = 0; i &#x3C; slots.size(); i++)
       {
              auto it = slots[i].find(name);
	       if (it != slots[i].end())
	       {
                     printf("That slot is already set up");
                     return;
               }
	}
	map&#x3C;wstring, int> map;
	map[name] = slot;
	slots.push_back(map);

	if (slot > maxSlotNumber) {
	       maxSlotNumber = slot;
	}
   }
   
   int ShaderSlot::GetSlotNumber(wstring name)
   {
        for (int i = 0; i &#x3C; slots.size(); i++)
        {
            auto it = slots[i].find(name);
	    if (it != slots[i].end())
	    {
<strong>		return it->second;
</strong>	    }
	}
   }
</code></pre>

3. Shader 클래스의 리소스 바인딩 메서드는 ShaderSlot을 통해 이름으로 슬롯을 찾고 해당 슬롯에 리소스를 바인딩합니다:

```
void Shader::PushShaderResourceToShader(ShaderType type, const wstring& name, UINT numViews, ComPtr<ID3D11ShaderResourceView> shaderResourceViews)
{
	UINT slot = _shaderSlot->GetSlotNumber(name);
	if (type == ShaderType::VERTEX_SHADER)
		DEVICECONTEXT->VSSetShaderResources(slot, numViews, shaderResourceViews.GetAddressOf());
	else if (type == ShaderType::DOMAIN_SHADER)
		DEVICECONTEXT->DSSetShaderResources(slot, numViews, shaderResourceViews.GetAddressOf());
	else if (type == ShaderType::GEOMETRY_SHADER)
		DEVICECONTEXT->GSSetShaderResources(slot, numViews, shaderResourceViews.GetAddressOf());
	else
		DEVICECONTEXT->PSSetShaderResources(slot, numViews, shaderResourceViews.GetAddressOf());
}
```

### <mark style="background-color:yellow;">RenderPass 클래스 - 렌더링 단계 관리</mark>

* **RenderPass 클래스는 특정 렌더링 기법이나 셰이더 효과를 구현하는 단일 렌더링 단계를 나타냅니다. MeshRenderer는 여러 RenderPass를 가질 수 있으며, 각 RenderPass는 다른 렌더링 기법을 적용합니다.**

```
class RenderPass
{
private:
    // 렌더링에 필요한 참조들
    weak_ptr<Transform> _transform;
    weak_ptr<MeshRenderer> _meshRenderer;
    shared_ptr<Shader> _shader;
    shared_ptr<Mesh> _mesh;
    shared_ptr<Texture> _texture;
    
    // 렌더링 상태 정보
    RenderPriority _priority = RenderPriority::NORMAL;
    D3D11_PRIMITIVE_TOPOLOGY _topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
    
public:
    // 렌더 패스 설정
    void SetTransform(shared_ptr<Transform> transform) { _transform = transform; }
    void SetMeshRenderer(shared_ptr<MeshRenderer> meshRenderer) { _meshRenderer = meshRenderer; }
    void SetShader(shared_ptr<Shader> shader) { _shader = shader; }
    void SetMesh(shared_ptr<Mesh> mesh) { _mesh = mesh; }
    void SetTexture(shared_ptr<Texture> texture) { _texture = texture; }
    
    // 렌더링 메서드
    void Render(bool isEnv = false);
    void DefaultRender(bool isEnv = false);
    void TerrainRender();
    void SkyBoxRender();
    void ParticleSystemRender();
    // ... 기타 렌더링 메서드 ...
};
```

RenderPass의 주요 기능:

1. 렌더링 상태 설정: 렌더링에 필요한 셰이더, 메시, 텍스처 등 설정                                                     (MeshRenderer가 가지고 있는 데이터를사용)
2. 렌더링 실행: 설정된 상태로 렌더링 수행
3. 다양한 렌더링 기법 지원: 기본 렌더링, Terrain, Skybox, ParticleSystem 등 특수 렌더링 구현

* **기본 렌더링 과정 예시:**

```
void RenderPass::DefaultRender(bool isEnv)
{
    // 셰이더 및 입력 레이아웃 설정
    auto inputLayout = _shader->GetInputLayout();
    CONTEXT->IASetInputLayout(inputLayout->GetInputLayout().Get());
    CONTEXT->VSSetShader(_shader->GetVertexShader().Get(), nullptr, 0);
    CONTEXT->PSSetShader(_shader->GetPixelShader().Get(), nullptr, 0);
    
    // 변환 행렬 상수 버퍼 설정
    auto transform = _transform.lock();
    _shader->PushConstantBufferToShader(ShaderType::VERTEX_SHADER, L"TransformBuffer", 1, transform->GetTransformBuffer());
    
    // 재질 상수 버퍼 설정
    auto meshRenderer = _meshRenderer.lock();
    auto materialBuffer = meshRenderer->GetMaterialBuffer();
    _shader->PushConstantBufferToShader(ShaderType::PIXEL_SHADER, L"MaterialBuffer", 1, materialBuffer);
    
    // 텍스처 설정
    if (_texture != nullptr)
        _shader->PushShaderResourceToShader(ShaderType::PIXEL_SHADER, L"DiffuseMap", 1, _texture->GetShaderResourceView());
    
    // 메시 버퍼 및 토폴로지 설정
    auto buffer = _mesh->GetBuffer();
    UINT stride = buffer->GetStride();
    UINT offset = buffer->GetOffset();
    CONTEXT->IASetVertexBuffers(0, 1, buffer->GetVertexBuffer().GetAddressOf(), &stride, &offset);
    CONTEXT->IASetIndexBuffer(buffer->GetIndexBuffer().Get(), DXGI_FORMAT_R32_UINT, 0);
    CONTEXT->IASetPrimitiveTopology(_topology);
    
    // 그리기 호출
    auto indexCount = _mesh->GetGeometry()->GetIndices().size();
    CONTEXT->DrawIndexed(indexCount, 0, 0);
}
```

* **MeshRenderer 클래스는 여러 RenderPass를 관리하며, RenderManager는 이 RenderPass들을 적절한 순서로 실행합니다:**

```
// MeshRenderer.h
private:
    vector<shared_ptr<RenderPass>> _renderPasses;
    
// RenderManager.cpp
void RenderManager::DrawRenderableObject(bool isEnv)
{
    // 모든 렌더링 가능 오브젝트 순회
    for (const shared_ptr<GameObject>& gameObject : _renderObjects)
    {
        shared_ptr<MeshRenderer> meshRenderer = gameObject->GetComponent<MeshRenderer>();
        
        // 모든 렌더 패스 실행
        for (int i = 0; i < meshRenderer->GetRenderPasses().size(); i++)
        {
            shared_ptr<RenderPass> renderPass = meshRenderer->GetRenderPasses()[i];
            renderPass->Render(isEnv);
        }
    }
    
    // 인스턴싱 렌더링 등 추가 처리
    // ...
}
```

이러한 방식으로, Material은 셰이더, 텍스처, 상수 버퍼를 관리하고, Shader는 ShaderSlot을 통해 리소스를 바인딩하며, RenderPass는 이 모든 요소를 활용하여 실제 렌더링을 수행합니다. 이 구성 요소들의 조화로운 상호 작용이 3D 렌더링 시스템의 기반을 이룹니다.

## <mark style="background-color:yellow;">렌더링 프로세스 전체 흐름</mark>

1. Material 초기화:
   1. 셰이더 설정
   2. 텍스처 설정
   3. 재질 속성 설정
   4. 상수 버퍼 생성 및 데이터 업로드
2. RenderPass 설정:
   1. 메시, 셰이더, 텍스처 참조 설정
   2. 렌더링 상태 구성
3. 렌더링 실행:
   1. RenderManager가 모든 렌더링 가능 오브젝트 수집
   2. 각 오브젝트의 모든 RenderPass 순차적으로 실행
   3. 각 RenderPass에서:
      1. 셰이더 설정
      2. 상수 버퍼 바인딩 (변환 행렬, 재질 속성)
      3. 텍스처 바인딩
      4. 정점 및 인덱스 버퍼 설정
      5. 그리기 호출


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://jihoon-jungs-organization.gitbook.io/jihoon_engine/feature-and-description/meshrenderer.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
