기술이 발전함에 따라 게임 그래픽은 점점 더 사실적이게 변하고
그에 따라 하드웨어도 눈부신 성장을 이루어 냈습니다.
그러나 우리 게임 엔지니어들은 항상 고민을 해왔습니다.
어떻게 하면 최소한의 자원으로 동일한 효과를 낼 수 있을까?
정말 수많은 최적화 기법들이 있지만 오늘 소개해드릴 최적화 기법은 바로 Matarial Sorting입니다.
말 그대로 Matrial을 Sorting(정렬)한다는 것입니다.
그렇다면 어째서 이 Matarial을 정렬해야 하며 정렬을 한다면 어떠한 기준으로 정렬을 해야 하는것일까요?
Matarial을 정렬해야 하는 이유
게임 월드상에는 다양한 Matarial을 가진 오브젝트들이 있을것입니다.
그렇다면 GPU는 각 오브젝트마다 Matarial을 바꿔끼면서 Draw연산을 수행하여야 합니다.
그런데 GPU가 Matarial을 바꾸는 것은 꾀나 비용이 큰 연산입니다.
그러므로 같은 Matarial을 가진 오브젝트끼리 정렬을 해서 연산을 수행하게 된다면
Matarial을 바꾸는 횟수를 최소화 할 수 있고 결론적으로 성능 향상을 기대할 수 있게 됩니다.
Matarial을 정렬하는 기준
위에서 이미 언급되었지만 같은 Matarial을 가진 오브젝트별로 묶어서 정렬됩니다.
그렇게되면 GPU가 Matarial을 바꾸는 횟수를 최소화 할 수 있습니다.
그림으로 보면 만약 Render해야하는 Object Pool에 이런식으로 정렬되지 않은 상태라면
오브젝트를 그릴때마다 계속해서 Matarial을 변경하는 로직을 수행해야 합니다.
만약 이렇게 Matarial Sorting이 진행되어서 같은 Matarial을 가진 Object끼리 묶여 있다면
단 한번의(Matarial이 2종류일 경우) Matarial변경으로 Rendering이 가능합니다.
StaticMeshObjs라는 TArray는 현재 정렬되지 않은 StaticMeshComponent들을 담고 있습니다.
이상태로 사과 오브젝트 50,000개를 생성하게 되면 FPS는 7까지 떨어지게 됩니다.
이것은 Matarial을 정렬하는 함수입니다.
FStaticMatarial을 Key로하는 unorderedmap에 모든 오브젝트들을 넣고있습니다.
std::unordered_map<FStaticMaterial*, std::vector<UStaticMeshComponent*>> SortedMesh;
void FRenderer::SortMeshesByMaterial()
{
// 정렬이 이미 되어 있으면 다시 할 필요 없음
if (!SortedMesh.empty())
return;
// 메시들을 재질별로 정렬
for (UStaticMeshComponent* StaticMeshComp : StaticMeshObjs)
{
if (!StaticMeshComp->GetStaticMesh()) continue;
OBJ::FStaticMeshRenderData* renderData = StaticMeshComp->GetStaticMesh()->GetRenderData();
if (renderData == nullptr) continue;
// 메시에서 사용할 재질을 가져옴
for (int subMeshIndex = 0; subMeshIndex < renderData->MaterialSubsets.Num(); subMeshIndex++)
{
int materialIndex = renderData->MaterialSubsets[subMeshIndex].MaterialIndex;
FStaticMaterial* Mat = StaticMeshComp->GetStaticMesh()->GetMaterials()[materialIndex];
// 재질별로 메시를 정렬
SortedMesh[Mat].push_back(StaticMeshComp);
}
}
}
그 이후 반복문을 돌때엔 SortedMesh를 기준으로 Render을 하면 됩니다.
극적인 개선효과는 아니지만 7 > 10까지 3FPS정도 증가한 모습을 보이고 있습니다.
좀더 극적인 렌더링 개선효과를 내기 위해서는 전체적인 Draw Call을 줄이거나 Octree, KD-Tree, BVH같은 공간분할 기법이나 Culling을 사용하는 것이 더 큰 효과를 낼 것으로 보입니다.
이상으로 최적화 기법중 하나인 Matarial Sorting에 대한 글을 마칩니다.
'DirectX11' 카테고리의 다른 글
[DX11] 안개 구현: Render Path 분리 (Full Quad Rendering) (0) | 2025.04.05 |
---|---|
[DX11] PIE Mode, Shallow/Deep Copy (깊은 복사/ 얕은 복사) (0) | 2025.04.03 |
[DX11] Constant Buffer에 값 넘길 때 주의할 점(Shader로 Matarial값 넘길 때 주의할점) (0) | 2025.03.26 |
[DX11] Shader에 Vertex넘길 때 주의 해야 할 점!! (Shader 디버깅 Tip) (0) | 2025.03.25 |
[DX11] UV좌표를 활용한 Text 렌더링 (0) | 2025.03.19 |