| 용어 | 설명 |
|---|---|
| VertexTextureData | Vec3(위치) + Vec2(UV 좌표)를 포함한 정점 구조체 |
| StackCount | Sphere의 수직 분할 수 (위에서 아래로) |
| SliceCount | Sphere의 수평 분할 수 (둘레 방향) |
| Grid | 정해진 수의 정점을 기반으로 구성된 격자형 평면 |
| Wrap / Clamp | UV 좌표가 [0, 1] 범위를 벗어났을 때 텍스처 샘플링 방식 |
| Wireframe | 도형의 외곽선만 렌더링해 구조 확인하는 모드 |
vector<VertexTextureData> vtx(24);
// 앞면부터 오른쪽면까지 각각 4개의 정점에 UV 설정
vtx[0] = VertexTextureData{ Vec3(-w2, -h2, -d2), Vec2(0.f, 1.f) }; // 앞면 좌하단
...
vtx[23] = VertexTextureData{ Vec3(+w2, -h2, +d2), Vec2(1.f, 1.f) }; // 오른쪽면 우하단
vector<uint32> idx(36);
idx[0] = 0; idx[1] = 1; idx[2] = 2; // 앞면 첫 삼각형
idx[3] = 0; idx[4] = 2; idx[5] = 3; // 앞면 두 번째 삼각형
...
idx[33] = 20; idx[34] = 22; idx[35] = 23; // 오른쪽면
각 면마다 정점을 독립적으로 사용하는 이유는 서로 다른 UV 좌표를 지정하기 위해서이다.
v.position = Vec3(0.f, radius, 0.f); // 북극
v.uv = Vec2(0.5f, 0.f); vtx.push_back(v);
for (uint32 y = 1; y <= stackCount - 1; ++y)
{
float phi = y * stackAngle;
for (uint32 x = 0; x <= sliceCount; ++x)
{
float theta = x * sliceAngle;
v.position = ... // 삼각함수로 X, Y, Z 계산
v.uv = Vec2(deltaU * x, deltaV * y);
vtx.push_back(v);
}
}
v.position = Vec3(0.f, -radius, 0.f); // 남극
v.uv = Vec2(0.5f, 1.0f); vtx.push_back(v);
for (uint32 i = 0; i < sliceCount; ++i)
{
idx.push_back(0);
idx.push_back(i + 2);
idx.push_back(i + 1);
}
for (uint32 y = 0; y < stackCount - 2; ++y)
{
for (uint32 x = 0; x < sliceCount; ++x)
{
idx.push_back(...); // 위쪽 삼각형
idx.push_back(...); // 아래쪽 삼각형
}
}
uint32 bottom = vtx.size() - 1;
uint32 lastRing = bottom - (sliceCount + 1);
for (uint32 i = 0; i < sliceCount; ++i)
{
idx.push_back(bottom);
idx.push_back(lastRing + i);
idx.push_back(lastRing + i + 1);
}
for (int32 z = 0; z <= sizeZ; ++z)
{
for (int32 x = 0; x <= sizeX; ++x)
{
VertexTextureData v;
v.position = Vec3(x, 0, z);
v.uv = Vec2(static_cast<float>(x) / sizeX, static_cast<float>(z) / sizeZ);
vtx.push_back(v);
}
}
UV 좌표는 정규화된 텍스처 범위(0~1)로 맞춰주는 것이 좋음
for (int32 z = 0; z < sizeZ; ++z)
{
for (int32 x = 0; x < sizeX; ++x)
{
int row = sizeX + 1;
// 삼각형 1
idx.push_back((z + 1) * row + x);
idx.push_back(z * row + x + 1);
idx.push_back(z * row + x);
// 삼각형 2
idx.push_back(z * row + x + 1);
idx.push_back((z + 1) * row + x);
idx.push_back((z + 1) * row + x + 1);
}
}
인덱스를 시계 방향으로 배치해 와인딩 순서를 유지해야 정상 렌더링됨
이로써 Geometry 도형 생성 강의에 대한 완전 분석 및 교육용 교재 재작성이 완료되었습니다.
다음 단계로 Material 및 MeshRenderer 통합, SamplerState 구성, 텍스처 타일링 처리까지 확장하실 수 있습니다. 필요하시면 바로 이어서 정리해드릴게요!