3D Tiles란 무엇인가

대용량 3D 지리공간 데이터를 웹/모바일에서 스트리밍 렌더링하기 위한 OGC 표준. 이 문서는 표준의 핵심 개념과 데이터 구조를 정리한다.


핵심 요약

구분내용
📖 정의Cesium이 설계하고 2019년 OGC 커뮤니티 표준이 된, 대용량 3D 데이터 계층 스트리밍 규격
💡 핵심공간 트리(quadtree/octree) + 거리 기반 LOD(SSE) + 콘텐츠 메타데이터의 결합
🎯 대상도시 스케일 3D, BIM, 포인트 클라우드, 지형, 인스턴스 객체를 웹에서 렌더링하는 개발자
⚠️ 주의2D 타일맵(Slippy Map)과는 트리 구조·LOD 선택 방식 모두 다르다

문서 탐색


목차

  1. 기본 개념
  2. 2D 타일맵과의 차이
  3. HLOD(Hierarchical Level of Detail) 원리
  4. Tileset.json 구조
  5. boundingVolume — 3가지 종류
  6. refine — ADD vs REPLACE
  7. geometricError와 SSE
  8. Implicit Tiling vs Explicit Tiling
  9. 콘텐츠 포맷

기본 개념

3D Tiles는 현실 세계의 대용량 3D 데이터를 효율적으로 분할·스트리밍하기 위한 데이터 포맷이다.

  • 도심 전체 건물, 수십억 포인트의 라이다(LiDAR), 광역 지형 메시는 단일 파일로 GPU에 올릴 수 없다.
  • 3D Tiles는 이런 데이터를 계층적 공간 트리로 분할하고, 카메라 거리·시야각에 따라 필요한 부분만 점진적으로 로드한다.
해결하는 문제방법
메모리/GPU 한계 초과화면에 보이는 타일만 로드
원거리 렌더링 품질 저하거리별 단순화 모델(LOD) 제공
복합 데이터 타입 혼재건물·포인트 클라우드·지형·인스턴스 모델을 동일 트리에 결합
시맨틱 정보 전달각 피처(건물 1동 등)에 속성 메타데이터 연결

표준 채택 이력

날짜이벤트
2015Cesium이 3D Tiles 개념 공개
2019-01OGC 3D Tiles 1.0 커뮤니티 표준 채택 (문서 번호 18-053r2)
2021-11”3D Tiles Next” 블로그 발표 (1.1의 전신)
2022-12-17OGC 3D Tiles 1.1 커뮤니티 표준 채택 (22-025r4)

2D 타일맵과의 차이

흔히 쓰는 웹 지도 타일(Slippy Map, OSM 등)과는 근본적으로 구조가 다르다.

[ Slippy Map (2D) ]                 [ 3D Tiles ]
  z/x/y 정수 좌표로 식별              트리 구조, 각 노드가 바운딩 볼륨 보유
  래스터 이미지(PNG/JPEG)             3D 지오메트리 + 속성 메타데이터
  고정된 줌 레벨(0~22)                연속적 geometricError 기반 LOD
  위도/경도 2D 범위만 기술            region/box/sphere 3D 공간 범위 기술
  타일 크기 일정(256px / 512px)       타일마다 크기·형태가 다를 수 있음
  렌더러가 단순 이미지 붙임           렌더러가 3D 씬 그래프 구성

가장 근본적인 차이는 “화면 픽셀 오차(SSE) 기반 동적 해상도 선택” vs **“고정 줌 레벨 기반 타일 선택”**이다. 3D Tiles는 줌 레벨이라는 개념이 없고, “지금 이 거리에서 이 타일을 더 잘게 쪼개야 하는가?”를 매 프레임 판단한다.


HLOD(Hierarchical Level of Detail) 원리

HLOD는 공간 트리의 각 노드가 하위 노드들의 단순화된 대표 표현을 갖는 구조다.

Root (geometricError=512m)
  전체 도심을 단순 박스 메시로 표현
  └─ Level 1 (geometricError=128m)
       구역별 건물 군집 표현
       └─ Level 2 (geometricError=32m)
            블록별 건물 실루엣
            └─ Level 3 (geometricError=4m)
                 개별 건물 외벽 상세
                 └─ Level 4 (geometricError≈0m)
                      창문·텍스처 최고 상세

뷰어는 카메라와 타일 사이 거리·FOV·화면 해상도를 조합해 **Screen Space Error(SSE)**를 계산한다.

  • SSE ≥ 임계값(기본 16px) → 자식 타일을 로드하고 렌더링
  • SSE < 임계값 → 현재 노드의 단순화 표현으로 충분 (하위 로드 중단)

이 방식 덕분에 **“멀리 있는 건물은 박스, 가까운 건물은 창문까지”**를 동시에 표현할 수 있다.


Tileset.json 구조

타일셋의 진입점은 항상 tileset.json이다. 이 안에 트리의 루트와 메타데이터가 들어있다.

{
  "asset": {
    "version": "1.1",          // 사양 버전 (필수)
    "tilesetVersion": "1.2.3"  // 사용자 정의 데이터 버전 (선택)
  },
  "geometricError": 512,       // 루트의 최대 허용 오차 (미터)
  "root": {
    "boundingVolume": { "region": [...] },
    "geometricError": 256,
    "refine": "REPLACE",
    "content": { "uri": "root.glb" },
    "children": [
      {
        "boundingVolume": { "box": [...] },
        "geometricError": 64,
        "content": { "uri": "child_0.glb" }
      }
    ]
  },
  "schema": { ... },           // 1.1 신규: 메타데이터 스키마
  "groups": [ ... ],           // 1.1 신규: 콘텐츠 그룹
  "metadata": { ... }          // 1.1 신규: 타일셋 수준 메타데이터
}
필드필수 여부설명
asset.version필수"1.0" 또는 "1.1"
geometricError필수루트 노드의 기하 오차(미터)
root필수최상위 타일 객체
root.boundingVolume필수공간 범위
root.geometricError필수이 타일의 단순화 오차
root.refine루트에서 필수"ADD" 또는 "REPLACE"
root.content선택렌더링할 파일 URI
root.children선택자식 타일 배열
schema선택(1.1)메타데이터 클래스·속성 타입 정의

출처: CesiumGS/3d-tiles tileset.schema.json


boundingVolume — 3가지 종류

각 타일은 자기 콘텐츠가 차지하는 3D 공간 범위(=바운딩 볼륨)를 가진다. 뷰 절두체 컬링(frustum culling)과 SSE 계산에 모두 사용된다.

region (지리 좌표계 / WGS84)
  [west, south, east, north, minHeight, maxHeight]
  단위: 경도·위도 rad, 높이 m
  용도: 지구 표면을 덮는 대면적 지형·도시 타일

  ┌─────────────────┐
  │  north          │
  │  west    east   │ ← 경위도 바운딩 박스 + 최소·최대 고도
  │  south          │
  └─────────────────┘

box (직교 좌표계 OBB)
  [cx,cy,cz, hx,hy,hz, rx,ry,rz, tx,ty,tz]  (12개 값)
  센터 + 3개의 반축 벡터
  용도: 회전된 건물·교량 등 임의 방향 객체

  ┌──────/
  │     /│  ← 임의 방향 Oriented Bounding Box
  │    / │
  └───/──┘

sphere (구)
  [cx, cy, cz, radius]  (4개 값)
  용도: 포인트 클라우드, 구형 분포 데이터

     ⊙  ← 중심점 + 반지름
종류값 개수좌표계적합한 용도
region6WGS84 지리대면적 지형·도시
box123D 직교(OBB)건물·인프라·CAD
sphere43D 직교포인트 클라우드

주의: boundingVolume은 실제 콘텐츠보다 약간 크게 설정해야 클리핑 아티팩트가 없다.


refine — ADD vs REPLACE

타일이 자식을 가질 때, “자식이 부모를 대체하는가, 부모 위에 얹히는가”를 결정한다.

REPLACE (치환 방식)          ADD (추가 방식)
─────────────────            ─────────────────
Parent ─┐                    Parent ─┐
        ├── Child A                  ├── Child A  (+ Parent도 렌더)
        └── Child B                  └── Child B  (+ Parent도 렌더)

자식 로드 시 부모를          자식 로드 시 부모와
  '대체'하여 렌더링           자식을 '동시에' 렌더링
refine동작적합한 데이터
REPLACE자식이 부모를 완전히 교체건물·지형·BIM (각 LOD가 완전한 표현)
ADD자식이 부모 위에 더해짐포인트 클라우드 (자식이 부모의 부분 세부화)

geometricError와 SSE

geometricError는 **“이 타일의 단순화 표현이 원본 데이터에 대해 가지는 오차(미터)“**다. 값이 클수록 더 거친 표현이다.

뷰어는 매 프레임 SSE(Screen Space Error)를 계산해 LOD 결정에 쓴다.

SSE 계산식

SSE = (geometricError × screenHeight) / (distance × 2 × tan(FOV/2))
  • screenHeight: 화면 높이(픽셀)
  • distance: 카메라와 타일 사이 거리(미터)
  • FOV: 수직 시야각(라디안)

예시

geometricError=10m, screenHeight=1080px, distance=500m, FOV=60°(π/3) 일 때:

SSE = (10 × 1080) / (500 × 2 × tan(30°))
    = 10800 / (500 × 1.1547)
    = 10800 / 577.35
    ≈ 18.7 px

18.7px > 임계값 16px 이므로 자식 타일 로드 필요.

조건판단
SSE ≥ maximumScreenSpaceError (기본 16)자식 로드 필요 (refine 실행)
SSE < maximumScreenSpaceError현재 타일로 충분 (하위 로드 중단)

CesiumJS의 tileset.maximumScreenSpaceError 값을 키우면 더 거친 LOD를 허용 → 메모리·대역폭 절약. 값을 줄이면 더 선명하지만 더 많은 타일 로드.


Implicit Tiling vs Explicit Tiling

Explicit Tiling (1.0 기본 방식)

모든 타일의 메타데이터를 JSON에 명시적으로 나열한다.

tileset.json
  └─ root tile
       ├─ child0.json (subtileset)
       │    ├─ tile_0_0.b3dm
       │    └─ tile_0_1.b3dm
       └─ child1.json
            ├─ tile_1_0.b3dm
            └─ tile_1_1.b3dm
  • 장점: 비균일 데이터(밀도가 들쭉날쭉한 경우)에 유연
  • 단점: 수백만 타일이면 tileset.json이 수 GB가 된다

Implicit Tiling (1.1 표준화)

좌표 규칙으로 타일을 주소화하고, 존재 여부를 비트스트림으로 저장한다.

tileset.json
  └─ root (implicitTiling 설정)
       subdivisionScheme: "QUADTREE" | "OCTREE"
       subtreeLevels: 4
       availableLevels: 20
       subtrees: { uri: "subtrees/{level}/{x}/{y}.subtree" }

각 .subtree 파일 (availability bitstream)
  ┌─ tileAvailability        (해당 좌표 타일 존재 여부)
  ├─ contentAvailability     (콘텐츠 파일 존재 여부)
  └─ childSubtreeAvailability (하위 subtree 존재 여부)
  • 좌표 (level, x, y) 또는 (level, x, y, z) 규칙으로 타일 주소화
  • Morton Z-order 곡선으로 비트스트림 정렬
  • 타일 존재 여부를 비트 1개로 표현 → 극도로 압축된 인덱스

비교표

비교 항목ExplicitImplicit
메타데이터 저장각 타일을 JSON에 나열비트스트림 subtree 파일
공간 탐색JSON 파싱 필요Morton code → 직접 계산
적합한 데이터비균일 밀도 데이터규칙적 격자(지형, 포인트 클라우드)
랜덤 접근어려움좌표 계산만으로 즉시 접근

콘텐츠 포맷

각 타일의 content.uri가 가리키는 실제 데이터 파일.

1.0 레거시 포맷

포맷약자용도
b3dmBatched 3D Model건물 등 여러 독립 모델을 한 타일에 batch
i3dmInstanced 3D Model동일 모델을 여러 위치에 인스턴싱 (나무, 가로등)
pntsPoint Cloud라이다·포토그래메트리 포인트 클라우드
cmptComposite여러 타일 포맷을 하나로 묶은 컨테이너
vctrVectorGeoJSON 스타일 벡터 (1.0 확장 제안, 표준화 실패)

b3dm 파일 레이아웃 예시:

┌──────────────────────────────────────┐
│  헤더 (28 bytes)                     │
│  magic="b3dm", version, byteLength,  │
│  featureTableJSONByteLength,         │
│  featureTableBinaryByteLength,       │
│  batchTableJSONByteLength,           │
│  batchTableBinaryByteLength          │
├──────────────────────────────────────┤
│  Feature Table JSON                  │
├──────────────────────────────────────┤
│  Feature Table Binary (선택)         │
├──────────────────────────────────────┤
│  Batch Table JSON (속성 메타데이터)   │
├──────────────────────────────────────┤
│  Batch Table Binary (선택)           │
├──────────────────────────────────────┤
│  glTF Binary (GLB)                   │
└──────────────────────────────────────┘
  • Batch Table: 각 객체(배치 ID)에 이름·층수·용도 등 속성 저장
  • Feature Table: BATCH_LENGTH, RTC_CENTER 등 렌더링 메타데이터

1.1 — glTF 직접 사용

1.1부터 .glb(Binary glTF 2.0) 파일을 타일 콘텐츠로 직접 참조한다. b3dm 같은 래퍼가 사라지고 glTF 확장(EXT_mesh_features 등)이 그 역할을 흡수한다.

자세한 1.0 → 1.1 변경점은 1.2 3D Tiles 1.0 vs 1.1에서 다룬다.


문서 탐색


참고 자료