UV Island와 Texture Atlas

UV island를 atlas에 잘 배치하는 것이 3D 타일링에서 텍스처 용량을 줄이는 핵심이다. 이 문서는 그 작업을 이해하는 데 필요한 모든 용어를 정의하고, UV 언래핑 → 패킹 → 베이크까지의 흐름을 정리한다.


핵심 요약

구분내용
📖 정의UV island = seam으로 분리된 UV 공간의 독립 영역. Atlas = 여러 island를 하나의 텍스처에 묶은 것
💡 핵심좋은 atlas = 높은 pack ratio + 균일한 texel density + 안전한 padding
🎯 대상3D Tiles, glTF, 게임 엔진에서 텍스처를 다루는 모든 개발자
⚠️ 주의seam·bleeding을 무시하면 mipmap에서 줄무늬 아티팩트가 발생한다

문서 탐색


목차

  1. 용어 정의 — 한 번에 정리
  2. Padding / Bleed / Gutter / Mipmap Padding
  3. UV Unwrapping 알고리즘
  4. Atlas Packing 5단계 흐름
  5. Texel Density 균일화
  6. Pack Ratio 측정과 목표값
  7. glTF / 3D Tiles 적용
  8. 자주 발생하는 문제

용어 정의 — 한 번에 정리

UV Mapping

3D 메쉬 표면을 2D 평면(UV 공간)으로 펼쳐서, 텍스처 이미지의 어느 점이 3D 표면의 어느 점에 대응하는지 정의하는 과정. “U”와 “V”는 2D 좌표축 이름(X·Y 대신 사용)으로, 보통 0.0~1.0 범위를 가진다.

UV Coordinate / UV Space

UV 좌표는 2D 텍스처 공간 위의 점 (u, v) 이며, 각 축은 통상 0.0~1.0 범위(= 1 UV 타일)이다. UV space는 이 2D 좌표계 전체를 지칭한다. 3D 메쉬의 각 vertex마다 UV 좌표가 하나씩 할당된다.

UV Island (= UV Chart)

3D 메쉬 (큐브 6면)              UV Space (펼친 후)
                                  ┌──┐
   ┌──┐                        ┌──┤  ├──┐
   │  │                        │  │  │  │  ← 6개의 island
   └──┘                        └──┤  ├──┘
                                  └──┘

하나의 메쉬를 UV 공간으로 펼쳤을 때, seam(절단선)으로 분리된 독립적인 연결 영역 하나. 예: 큐브를 전개도로 폈을 때 각 면이 하나의 island.

xatlas에서는 “chart”라는 용어를 동일한 의미로 사용한다.

UV Seam (절단선)

3D 메쉬에서 UV 전개 시 잘라내는 경계 엣지.

세임 많음세임 적음
Island 많이 분리Island 적음
왜곡(stretch) 적음왜곡 큼
Pack 효율 좋음Pack 효율 떨어짐

인간 모델의 뒷머리·몸통 솔기처럼 시각적으로 눈에 띄지 않는 위치에 배치하는 것이 관례.

UV Unwrapping

3D 표면을 UV 공간의 2D 평면으로 ‘펼치는’ 작업. seam을 따라 메쉬를 잘라 island들을 만들고, 각 island를 왜곡 최소화 알고리즘(LSCM 등)으로 2D에 투영한다. 결과로 각 vertex에 UV 좌표가 생성된다.

Texture Atlas

여러 개의 독립적인 텍스처(또는 UV island)를 하나의 큰 텍스처 이미지에 합쳐 놓은 것.

효과설명
드로우콜(draw call) 감소머티리얼 스왑 횟수 ↓
GPU 메모리 효율 ↑단일 텍스처로 캐시 효율 ↑
스트리밍 최적화3D Tiles에서 타일 1개에 텍스처 1장
KTX2/ETC1S 압축 효율 ↑Global codebook 공유로 10~40% 추가 절감

Atlas Packing

여러 UV island(chart)를 단일 atlas 텍스처 공간 안에 낭비 없이 배치하는 작업. 2D bin packing 문제의 응용. 자세한 알고리즘은 3.1 Bin Packing 참고.

Texel

Texture element의 줄임말. 텍스처 이미지의 가장 작은 단위인 단일 픽셀을 3D 맥락에서 부르는 이름. 3D 표면 위 면적이 텍스처 이미지에서 몇 개의 texel에 해당하는지가 품질의 핵심이다.

Texel Density (TD)

3D 표면의 단위 면적당 할당된 texel 수. 단위: texels/cm 또는 texels/m.

Texel Density = (texture_resolution × UV_island_area_ratio) / world_area_of_island

모든 island의 TD가 균일해야 텍스처 품질이 일관된다. TD 불일치 → 가까운 오브젝트는 흐릿하고 먼 오브젝트는 선명한 불균형.

UDIM (UV Tile)

UV space를 1×1 단위 타일 여러 장으로 확장하는 규격. 타일 번호는 1001부터 시작(예: 1002는 U 방향 한 칸).

UDIM 번호 체계
1001 (u=0~1, v=0~1)  1002 (u=1~2, v=0~1)  ...
1011 (u=0~1, v=1~2)  1012 (u=1~2, v=1~2)  ...

각 UDIM 타일 = 독립적인 텍스처 파일
예: mesh_basecolor.1001.png, mesh_basecolor.1002.png

VFX/게임 고해상도 캐릭터 텍스처에 사용. Blender 4.x, Houdini, Maya 모두 지원.

3D Tiles에서는 일반적으로 UDIM보다 단일 atlas가 선호된다. glTF 표준은 UDIM을 직접 지원하지 않으므로, UDIM 자산을 glTF로 변환할 때는 반드시 atlas로 재패킹해야 한다.

Power-of-Two (POT)

가로·세로 해상도가 2의 거듭제곱(256, 512, 1024, 2048, 4096 등)인 텍스처.

이유설명
하드웨어 최적화GPU가 POT에서 mipmap 생성·메모리 정렬 최적
압축 포맷 요구ETC1S, ETC2, ASTC 등 모바일 압축이 사실상 POT 필수

Charts (xatlas 용어)

xatlas 라이브러리에서 UV island와 동의어로 쓰는 공식 용어. xatlas::ChartOptions로 chart 생성 파라미터를 제어한다.

Pack Ratio (활용도)

atlas 텍스처 전체 면적 대비 실제 UV island가 차지하는 면적의 비율.

pack_ratio = Σ(island 면적) / atlas 전체 면적 × 100 (%)
  • 높을수록 텍스처 공간 낭비가 적음
  • xatlas의 경우 atlasUtilization 값으로 반환
  • 실용 기준: 85% 이상 = 우수

Padding / Bleed / Gutter / Mipmap Padding

용어가 자주 혼용되지만 엄밀히 다르다.

용어정의목적
Paddingatlas 내 island 경계에서 인접 island까지의 최소 픽셀 여백island 간 색상 간섭 방지
Marginatlas 테두리(외곽)에서 island까지의 여백텍스처 경계 클램핑 오류 방지
Bleeding (Bleed)island 경계 픽셀의 색을 바깥쪽으로 복사해 채우는 작업필터링/밉맵 시 경계 줄무늬 방지
GutterPadding + Bleeding이 합쳐진 영역 전체를 지칭위 모든 목적 포괄
┌───────────────────────────────────────┐
│ ← margin →                            │
│       ┌──────────────────┐            │
│       │                  │            │
│       │   Island A        │ ←padding→ │
│       │ (UV 영역)         │           │
│       │                  │            │
│       └──bleed (외곽 dilation)        │
│                                       │
│                ┌──────────────────┐   │
│                │   Island B       │   │
│                └──────────────────┘   │
└───────────────────────────────────────┘

Mipmap Padding

Mipmap 생성 시 텍스처를 반으로 줄여가므로, N단계 mipmap을 사용하면 island 사이 여백이 2^N 픽셀 이상이어야 한다.

Mipmap 단계최소 권장 padding
12 px
24 px
38 px
416 px
8 (이론값)256 px (비현실적)

실무 권장: 2048px atlas, mipmap 3~4단계 → padding 4~8 px + bleeding dilation 적용.


UV Unwrapping 알고리즘

LSCM (Least Squares Conformal Maps)

  • 논문: Lévy et al., 2002
  • 원리: 각도 왜곡(conformal distortion)을 최소화하는 선형 최소제곱 문제로 UV 좌표 산출
  • 장점: 계산 빠름, 구현 단순 → Blender 기본 Unwrap에 사용
  • 단점: 면적 왜곡이 클 수 있음 (넓은 면이 UV에서 작게/크게 나옴)
  • 적합: 유기체 표면, 캐릭터 얼굴 등 각도 보존이 중요한 경우

ABF / ABF++ (Angle-Based Flattening)

  • 논문: Sheffer et al., 2005
  • 원리: 각 삼각형 내각의 3D→2D 변화량을 직접 최소화하는 비선형 최적화
  • 장점: LSCM보다 각도 왜곡이 적음
  • 단점: 비선형 최적화로 계산 비용 ↑, 대형 메쉬에서 느림
  • 적합: 소형 메쉬의 고품질 언래핑

SLIM (Scalable Locally Injective Mappings)

  • 논문: Rabinovich et al., SIGGRAPH 2017
  • 원리: 각도·면적 왜곡을 동시에 최소화하는 반복 최적화. “Locally Injective”로 면 뒤집힘(flipped triangle) 수학적 방지
  • 장점: 현재 업계 최고 품질. 뒤집힘 없음 보장
  • 단점: 반복 계산으로 LSCM보다 느림
  • Blender 통합: Blender 4.3부터 Minimum Stretch 연산자로 공식 통합 (2024-11)
  • 적합: 모든 경우에 권장. 특히 복잡한 유기체 모델

Smart UV Project (Blender 내장)

카메라 시점 기준으로 법선(normal) 방향이 비슷한 면들을 그룹화해 평면 투영으로 island를 만든다. 빠르지만 seam 위치 제어가 어려움 → 박스·건축물 같은 각진 메쉬에 적합.

Boundary First Flattening (BFF)

  • 개발: Rohan Sawhney & Keenan Crane (CMU, 2018)
  • GitHub: https://github.com/GeometryCollective/boundary-first-flattening
  • 원리: 경계(boundary)를 먼저 자유롭게 지정한 뒤 내부를 등각사상(conformal mapping)으로 채움
  • 장점: 수백만 삼각형 실시간 처리, 경계 모양을 사용자가 완벽히 제어
  • 단점: 경계 지정에 전문 지식 필요
  • 적합: CAD, 정밀 해석, 특수 경계 형태 필요한 경우

알고리즘 비교표

알고리즘속도각도 왜곡면적 왜곡뒤집힘 방지구현 난이도
LSCM빠름낮음중간없음쉬움
ABF++느림매우 낮음낮음없음중간
SLIM중간낮음낮음보장어려움
BFF매우 빠름낮음중간없음중간
Smart UV매우 빠름높음중간없음없음(자동)

Atlas Packing 5단계 흐름

┌───────────────────────────────────────────────────────────────────┐
│                     Atlas Packing 전체 흐름                       │
└───────────────────────────────────────────────────────────────────┘

원본 3D 메쉬 (vertices, faces, normals)
         │
         ▼
┌─────────────────────────────┐
│  Step 1: Chart 분리           │
│  ─ seam detection (법선 각도) │
│  ─ 연결 컴포넌트 분리           │
│  ─ k-means / 법선 클러스터링   │
│    로 island 분할             │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│  Step 2: 각 Chart UV 계산   │
│  ─ LSCM / SLIM / ABF로      │
│    3D → 2D 매핑              │
│  ─ island별 독립 UV 좌표     │
│    (0~1 정규화)             │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│  Step 3: 2D Bin Packing     │
│  ─ island를 회전(0°/90°/    │
│    임의)하여 면적 최소화      │
│  ─ MaxRects / Skyline /     │
│    Guillotine 알고리즘       │
│  ─ atlas 크기 결정 (POT)     │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│  Step 4: Padding / Bleed    │
│  ─ island 경계에 N픽셀 여백 │
│  ─ 경계 픽셀 바깥으로 복사   │
│    (dilation / push-out)    │
│  ─ atlas 외곽 margin 확보   │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│  Step 5: Mipmap-safe 검증   │
│  ─ island 최소 크기 ≥ 4px   │
│  ─ 여백 ≥ 2^(mip단계)px     │
│  ─ 4px 블록 정렬 (ETC1S)    │
│  ─ POT 크기 확인             │
└─────────────┬───────────────┘
              │
              ▼
단일 Atlas Texture + 업데이트된 UV 좌표 → GLB/KTX2 저장

Texel Density 균일화

모든 island의 TD가 일치하지 않으면 동일 거리에서 보이는 디테일이 들쭉날쭉해진다.

나쁜 예 (TD 불균일)              좋은 예 (TD 균일)
──────────────────              ──────────────────
얼굴 200 texels/cm              얼굴 100 texels/cm
손  50  texels/cm               손  100 texels/cm
옷  150 texels/cm               옷  100 texels/cm

→ 얼굴은 선명, 손은 흐릿         → 전체적으로 균일한 품질

균일화 방법

  1. 자동 정규화: xatlastexels_per_unit 파라미터로 자동 균일화
  2. 수동 보정: Blender TexTools 애드온의 Texel Density 패널에서 island 단위 스케일 조정
  3. 시각화: Checker 패턴 텍스처를 임시 적용해 사각형 크기가 균일한지 확인

Pack Ratio 측정과 목표값

pack_ratio = Σ(island 면적) / atlas 면적 × 100 %
결과평가
< 50%매우 낭비. 재패킹 필수
50~70%일반적인 자동 패킹 (Smart UV + Pack Islands)
70~85%양호 (MaxRects 또는 Blender 4.3+ ANY rotation)
85~95%우수 (xatlas, UVPackmaster)
> 95%매우 우수, 다만 padding이 충분한지 검증 필요

Pack ratio만 높여도 padding이 부족하면 mipmap 아티팩트가 생긴다. 둘은 트레이드오프.


glTF / 3D Tiles 적용

glb 내 텍스처 저장 구조

GLB 파일 구조
┌──────────────┬──────────────────────────────────┐
│ JSON 청크    │ glTF JSON (메쉬, 재질, UV 참조)  │
├──────────────┼──────────────────────────────────┤
│ Binary 청크  │ vertex buffer + 텍스처 이미지     │
└──────────────┴──────────────────────────────────┘

JSON 내 텍스처 참조 경로:
mesh.primitives[i].attributes.TEXCOORD_0
  → accessors[j]                 (UV 좌표 float32 배열)
  → bufferViews[k] → buffer

mesh.primitives[i].material
  → materials[m].pbrMetallicRoughness.baseColorTexture.index
  → textures[n].source
  → images[p].bufferView          (PNG/JPEG/KTX2 바이너리)

Atlas 재패킹으로 텍스처 용량 절감

재패킹 전:                       재패킹 후:
─────────────                    ─────────────
창문 텍스처 1024×1024            단일 atlas 2048×2048
벽돌 텍스처 1024×1024            (창문 + 벽돌 + 지붕 통합)
지붕 텍스처 1024×1024
─────────────────                ─────────────────
드로우콜 3회                      드로우콜 1회
파일 수 3장                       파일 수 1장
ETC1S 압축률 개별 적용            Global codebook 공유 → 10~40% 추가 절감

KTX2/ETC1S 압축 전 Atlas 최적화의 중요성

ETC1S는 Global Codebook 방식. atlas 전체 픽셀을 분석해 팔레트를 생성한다.

atlas로 합치면 codebook이 텍스처 전체 색상을 공유 → 개별 압축 대비 파일 크기 10~40% 추가 절감 + GPU 메모리 캐시 효율 ↑.

meshopt / Draco와의 결합 순서

권장 파이프라인:
1. UV atlas 재패킹 (xatlas / Blender)
2. Texel density 균일화
3. 텍스처 이미지 합성 (Pillow)
4. KTX2 / ETC1S 또는 UASTC 압축
5. Draco 또는 meshopt로 geometry 압축

순서가 중요한 이유:

  • Draco는 vertex 재정렬을 한다 → UV 좌표도 재정렬됨 → atlas 재패킹은 반드시 Draco 이전에 완료
  • KTX2는 최종 단계: atlas 이미지 완성 후 압축

자주 발생하는 문제

문제원인해결법
Seam artifact (이음선 얼룩)island 경계 texel이 인접 island 색상으로 오염bleeding dilation 강화; padding 최소 4px; ETC1S 사용 시 4px 블록 정렬
Texel density 불일치island 크기가 3D 면적에 비례하지 않음xatlas texels_per_unit 통일; TexTools TD 균일화; 큰 island 세분화
POT 크기 초과atlas 크기가 4097px 등 비표준2^ceil(log2(n)) 반올림; pack_options.resolution 지정
Mipmap 블리딩island 간 여백 < 2^mip_level pxpadding을 max_mip_level × 2 이상
뒤집힌 UV islandLSCM에서 일부 island가 mirror됨xatlas는 자동 처리; Blender U → Mirror 수동 교정
Atlas 활용도 낮음island 회전 없음, 큰 여백rotation=True 활성화; UVPackmaster 임의 각도 회전
GLB 텍스처 미적용UV 인덱스 불일치 (xatlas vmapping 미적용)vmapping으로 vertex 재정렬 후 GLB 저장

문서 탐색


참고 자료