렌더링 파이프라인에서 첫 초기화시 몇가지 버퍼를 gpu에 메모리를 저장해야 합니다. 텍스쳐메모리, 각 메쉬의 vertex버퍼, constant버퍼등을 저장합니다. 하지만 초기화 시 mesh의 vertex들의 수가 많다면 시간이 오래 걸리게 됩니다. cpu에서 gpu로 데이터를 보내는데 시간이 오래걸리기 때문입니다. 따라서 gpu에 보내는 데이터의 크기를 줄이면 줄일수록 좋습니다.
subdivision의 개념은 어떠한 메쉬를 vertex의 수를 적게 그린 후, 각 삼각형을 4개로 분할하여 다시 그려주는 것입니다.
구를 예를들어 보자면, 다음 구는 vertex의 수를 적게 하고 그린 예시입니다.
하지만 여기서 삼각형을 여러개로 분할하면 어떻게 될까요?
다음 그림에서 삼각형을 이렇게 4개로 나눕니다.
새로 생긴 vertex들은 구의 표면에 있지 않기 때문에, 표면에 있도록 조정해줍니다. 그리고 새로운 vertex들과 index를 생성하여 newMesh를 생성합니다. 코드는 다음과 같습니다.
MeshData GeometryGenerator::SubdivideToSphere(const float radius,
MeshData meshData) {
using namespace DirectX;
using DirectX::SimpleMath::Matrix;
using DirectX::SimpleMath::Vector3;
// 원점이 중심이라고 가정
// 입력 받은 구 모델의 반지름 조절
for (auto &v : meshData.vertices) {
v.position = v.normal * radius;
}
// 구의 표면으로 옮기고 노멀 계산
auto ProjectVertex = [&](Vertex &v) {
v.normal = v.position;
v.normal.Normalize();
v.position = v.normal * radius;
};
// 버텍스가 중복되는 구조로 구현
MeshData newMesh;
uint16_t count = 0;
for (size_t i = 0; i < meshData.indices.size(); i += 3) {
size_t i0 = meshData.indices[i];
size_t i1 = meshData.indices[i + 1];
size_t i2 = meshData.indices[i + 2];
Vertex v0 = meshData.vertices[i0];
Vertex v1 = meshData.vertices[i1];
Vertex v2 = meshData.vertices[i2];
Vertex v3;
// 위치와 텍스춰 좌표 결정
v3.position = (v0.position + v1.position) / (float)2;
v3.texcoord = (v0.texcoord + v1.texcoord) / (float)2;
Vertex v4;
// 위치와 텍스춰 좌표 결정
v4.position = (v1.position + v2.position) / (float)2;
v4.texcoord = (v1.texcoord + v2.texcoord) / (float)2;
Vertex v5;
// 위치와 텍스춰 좌표 결정
v5.position = (v0.position + v2.position) / (float)2;
v5.texcoord = (v0.texcoord + v2.texcoord) / (float)2;
ProjectVertex(v3);
ProjectVertex(v4);
ProjectVertex(v5);
// 모든 버텍스 새로 추가
newMesh.vertices.push_back(v0);
newMesh.vertices.push_back(v1);
newMesh.vertices.push_back(v2);
newMesh.vertices.push_back(v3);
newMesh.vertices.push_back(v4);
newMesh.vertices.push_back(v5);
newMesh.indices.push_back(0 + count);
newMesh.indices.push_back(3 + count);
newMesh.indices.push_back(5 + count);
newMesh.indices.push_back(3 + count);
newMesh.indices.push_back(1 + count);
newMesh.indices.push_back(4 + count);
newMesh.indices.push_back(5 + count);
newMesh.indices.push_back(3 + count);
newMesh.indices.push_back(4 + count);
newMesh.indices.push_back(5 + count);
newMesh.indices.push_back(4 + count);
newMesh.indices.push_back(2 + count);
count += 6;
}
return newMesh;
}
이 subdivision을 두번 반복하면 결과는 다음과 같이 구와 가까운 형태가 됩니다.
주의할 점은 처음 구를 그릴 때, 텍스춰가 붙는 지점은 변하지 않으니 텍스춰가 잘려서 붙지 않도록 처음 vertex의 수가 너무 작지 않도록 해야합니다.
'Graphics Techniques' 카테고리의 다른 글
[Rendering Pipeline] 후처리 시 스왑체인과 백버퍼에 대한 이해 (0) | 2024.12.12 |
---|---|
[렌더링파이프라인] 구 Mapping의 원리 (0) | 2024.12.05 |
[Rasterization] 빛의 조명 3가지 (1) | 2024.11.11 |
[Rasterization] Blinn-Phone 모델(블린 퐁 모델) (0) | 2024.11.05 |
[Rasterization] 버텍스 쉐이딩과 픽셀 쉐이딩 개념 + 뒷면 제거 (0) | 2024.10.29 |