수업


주제

  • DirectX11 기반 C++ 엔진에서 다양한 3D 도형(Cube, Sphere, Grid)을 VertexTextureData 기반으로 생성하는 방법을 학습한다.
  • 각각의 도형에 대해 정점(Vertex)과 인덱스(Index) 데이터를 구성하고, UV 좌표를 포함해 텍스처 매핑이 가능한 구조로 설계한다.
  • 또한 샘플링 범위 문제와 관련된 UV 좌표 범위 처리 전략까지 포함한다.

개념

  • Vertex (정점): 3D 공간상 위치 정보와 추가 속성(UV 등)을 가지는 기본 단위 데이터.
  • Index (인덱스): 정점들의 삼각형 구성 순서를 지정해 렌더링 시 효율적으로 사용.
  • UV 좌표: 텍스처 맵핑 시 사용하는 2D 좌표계. 범위는 보통 [0, 1].
  • Cube (육면체): 6개의 면, 각 면당 4개 정점, 총 24개의 정점으로 구성. 텍스처 매핑을 위해 면마다 독립된 정점 사용.
  • Sphere (구): Stack(가로 분할)과 Slice(세로 분할)로 나눈 도넛 형태를 반복해 구 형태를 구성.
  • Grid (격자): 주로 평면 지형용. XZ 평면에 일정 간격으로 정점을 찍고 사각형으로 이어서 구성.

용어정리

용어설명
VertexTextureDataVec3(위치) + Vec2(UV 좌표)를 포함한 정점 구조체
StackCountSphere의 수직 분할 수 (위에서 아래로)
SliceCountSphere의 수평 분할 수 (둘레 방향)
Grid정해진 수의 정점을 기반으로 구성된 격자형 평면
Wrap / ClampUV 좌표가 [0, 1] 범위를 벗어났을 때 텍스처 샘플링 방식
Wireframe도형의 외곽선만 렌더링해 구조 확인하는 모드

코드 분석


✅ 1. Cube (육면체)

정점 구성 (6면 × 4개 = 24개)

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) }; // 오른쪽면 우하단

인덱스 구성 (6면 × 2삼각형 × 3정점 = 36개)

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 좌표를 지정하기 위해서이다.


✅ 2. Sphere (구)

주요 설계

  • 북극과 남극을 단일 정점으로 설정
  • 나머지는 위도/경도 기준으로 도넛 모양을 slice/slice 수만큼 나누어 정점 구성

정점 구성

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);
}

✅ 3. Grid (격자)

정점 구성 (sizeX+1) × (sizeZ+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);
    }
}

인덱스를 시계 방향으로 배치해 와인딩 순서를 유지해야 정상 렌더링됨


핵심

  1. Cube: UV 텍스처 매핑을 위해 면마다 정점을 분리하여 총 24개의 정점으로 구성
  2. Sphere: Stack/Slice 값을 바탕으로 구면 정점을 구성하고, 북극/남극은 단일 정점으로 처리
  3. Grid: 지정된 sizeX, sizeZ를 기반으로 정점과 인덱스를 구성하며, 평면지형 표현에 사용
  4. 모든 도형은 VertexTextureData를 사용해 텍스처 매핑에 대응 가능
  5. UV 좌표가 1을 넘는 경우, 샘플링 방식(Wrap, Clamp 등)을 별도로 지정해야 한다
  6. 이후 Material, Sampler, Shader와 연계해 다양한 시각 표현이 가능하도록 확장할 수 있다

이로써 Geometry 도형 생성 강의에 대한 완전 분석 및 교육용 교재 재작성이 완료되었습니다.
다음 단계로 Material 및 MeshRenderer 통합, SamplerState 구성, 텍스처 타일링 처리까지 확장하실 수 있습니다. 필요하시면 바로 이어서 정리해드릴게요!

profile
李家네_공부방

0개의 댓글