티스토리 뷰

Cesium/3D Tiles Formats

3D Tiles 1.0 주요 포맷 정리: B3DM

시뮬레이션 프로그래머 2025. 4. 20. 20:34

목차


3D Tiles 개요

3D Tiles는 대규모 3차원 공간 데이터를 웹에서 효율적으로 스트리밍하고 렌더링하기 위한 오픈 표준 포맷입니다.
주로 CesiumJS, Google Maps, NVIDIA Omniverse와 같이 3D GIS, BIM, LiDAR(점군), 스마트시티, 디지털 트윈 등에서 사용되며, 수천~수백만 개에 달하는 3D 객체를 LOD(Level of Detail) 기반으로 효율적으로 관리할 수 있게 도와줍니다.
 
3D Tiles는 1.0과 1.1 두 가지 주요 버전이 존재하며, 포맷 구조와 메타데이터 처리 방식이 변화했습니다.

구분 3D Tiles 1.0 3D Tiles 1.1
콘텐츠 포맷 .b3dm, .i3dm, .pnts, .glb .glb 통일
메타데이터 Batch Table + _BATCHID EXT_structural_metadata 확장
계층 구조 명시적 타일 (tileset.json) 암시적 타일링(.subtree) 도입
상태 현재도 많이 사용됨 차세대 표준으로 전환 중

 


B3DM(Batched 3D Model) 

B3DM은 여러 개의 glTF 모델을 하나의 파일로 묶어, 웹 브라우저에서 효율적으로 스트리밍하고 렌더링할 수 있도록 설계된 3D Tiles 콘텐츠 포맷입니다. 기본적으로 하나의 타일에 다양한 3D 객체(예: 건물, 구조물 등)를 포함시켜, 렌더링 성능을 향상시키고 데이터 스트리밍 비용을 최소화하는 것을 목적으로 합니다.
 

B3DM은 현재 레거시 포맷입니다.
3D Tiles 1.0에서 주로 사용한 B3DM은,
3D Tiles 1.1부터 glTF(.glb) 단일 포맷 EXT_structural_metadata 확장을 기반으로 한 구조로 대체되고 있으며,
기존의 Batch Table 방식은 점차 사용되지 않고 있습니다.

 

B3DM이 필요한 이유

예를 들어, 서울시의 건물 10,000개를 웹에서 렌더링해야 한다고 가정해보겠습니다.
각 건물을 별도의 glTF 파일로 처리한다면, 다음과 같은 문제가 발생합니다.

  • 10,000번의 HTTP 요청(glTF 파일) → 네트워크 트래픽 증가
  • 10,000번의 WebGL draw call → 브라우저 성능 저하
  • 모든 건물을 풀 디테일로 로딩 → 카메라가 멀어도 리소스 낭비 발생

결과적으로 로딩 속도는 느려지고, 시스템은 무거워지며, 사용자 경험이 저하됩니다.
 

B3DM이 제공하는 해결책

B3DM은 이러한 문제를 해결하기 위해, 여러 glTF 모델을 하나의 파일로 묶고 이를 공간적으로 배치(batch)합니다.
예를 들어, 서울시의 건물들을 전부 또는 행정구역 단위(예: 구, 동)로 나누어 각 그룹을 하나의 B3DM 파일로 생성할 수 있습니다. 서울시 건물을 하나의 B3DM 파일로 구성하면 다음과 같은 이점을 얻을 수 있습니다.

  • 단 1번의 HTTP 요청으로 10,000개 모델 로딩
  • 1번의 draw call로 10,000개 모델 렌더링
  • 카메라 거리나 필요에 따라 타일 단위로 지연 로딩(Lazy Loading)

하지만 예시로 서울시 모든 건물을 하나의 B3DM 파일로 구성했지만, 사용자의 카메라가 서울시 일부인 관악구만 보고 있는데도 서울시 전체 건물을 모두 로딩하게 되면 불필요한 리소스를 낭비하게 됩니다. 따라서 B3DM 단위로 모델을 적절하게 그룹화하는 전략 또한 매우 중요합니다. (= LOD Details)
 

B3DM 모델 단위의 식별성과 속성 관리

B3DM에 포함된 각 모델은 고유한 ID 속성(feature)을 가질 수 있습니다. 이를 통해 사용자는 특정 건물을 클릭하여 정보를 조회하거나, 속성 값에 따라 색상을 동적으로 변경하는 등 다양한 상호작용을 구현할 수 있습니다.

건물 정보 보기

예를 들어, 위 화면에서 계단을 클릭하면 다음과 같이 건물의 고유 ID를 기반으로 건물 정보를 조회하거나, 건물 타입에 따라 색상을 분류하는 등의 처리가 가능합니다. 

 

B3DM은 하나의 .b3dm 파일에 다수의 매시(mesh) 즉, 여러개의 건물을 가지고 있으므로, 매시에 대한 ID 정보와 해당 매시의 속성 정보를 바이너리 형태로 매칭 시킵니다.

 

예를 들어, 위 이미지에서 하나의 계단은 10개의 파랑색 직사각형과 2개의 빨간 직선이 매시를 이룬다고 가정하겠습니다. 이를 .b3dm으로 나타내면 10개의 파랑색 직사각형과 2개의 빨간 직선의 매시 정보들(점, 텍스처, 법선벡터 등)과 해당 각 매시(총 12개)에 대한 속성 정보, 그리고 그 속성정보가 어떤 매시에 속하는지 등의 정보가 B3DM 내부 구조 맨 뒤의 Binary glTF에 기록됩니다.

 

즉, B3DM은 단순히 여러 3D 모델을 묶는 것을 넘어, 각 모델에 대한 속성 정보와 상호작용 기능까지 포함하는 고성능 포맷입니다.
Cesium과 같은 뷰어에서는 B3DM을 기반으로 수천 개의 건물을 효율적으로 렌더링하고, 카메라 위치에 따라 필요한 타일만 선택적으로 스트리밍하여 사용자에게 빠르고 가벼운 3D 시각화 환경을 제공합니다.
 


B3DM 내부 구조

그림 1. Batched 3D Model 데이터 레이아웃

.b3dm 파일은 두 개의 주요 섹션으로 구성됩니다.
 
1. Header (고정 길이: 28 bytes)
2. Body (가변 길이)
    • Feature Table (* 필수): 타일 전반에 대한 메타데이터
    • Batch Table (선택): 각 개별 모델(feature)에 대한 속성값 
    • Binary glTF 또는 GlB (* 필수): 실제 3D 모델 데이터 (메시, 재질, 텍스처 등)

필드명 타입 설명
magic 4-byte string (4byte) 항상 "b3dm" (파일 식별자)
version uint32 (4byte) 포맷 버전 (현재 1)
byteLength uint32 (4byte) 타일 전체 길이 (header 포함)
featureTableJSONByteLength uint32 (4byte) Feature Table JSON의 바이트 길이
featureTableBinaryByteLength uint32 (4byte) Feature Table Binary의 바이트 길이
batchTableJSONByteLength uint32 (4byte) Batch Table JSON의 바이트 길이 (0이면 없음)
batchTableBinaryByteLength uint32 (4byte) Batch Table Binary의 바이트 길이 (없으면 0)

헤더는 타일 내 데이터들의 위치와 크기를 파악하기 위한 역할을 합니다.
 

B3DM Body

Body 데이터는 JSON과 Binary로 구분되는데, 다음과 같은 기준으로 이해하면 될 것 같습니다.

  • JSON: 구조 설명서 (어떤 데이터가 어디에 들어있는지 설명)
  • Binary: 실제 데이터 (위치, 노멀, 색상, batchId 등의 숫자 배열)

Body
   • Feature Table (* 필수): 타일 전반에 대한 메타데이터
   • Batch Table (선택): 각 개별 모델(feature)에 대한 속성값 
   • Binary glTF 또는 GlB (* 필수): 실제 3D 모델 데이터 (메시, 재질, 텍스처 등)
 

Feature Table (* 필수)

  • 타일 전반에 대한 메타데이터를 포함
    • BATCH_LENGTH(모델 수) (* 필수)
    • RTC_CENTER(좌표 기준점) (선택)
  • JSON + Binary로 구성되어 있으며, JSON만 있어도 충분

Feature Table JSON 예시

{
  "BATCH_LENGTH": 3,
  "RTC_CENTER": [127.12345, 37.56789, 100.0]
}

 

Feature Table Binary 예시

  • RTC_CENTER의 값 [127.12345, 37.56789, 100.0]을 float32로 인코딩한 바이트 시퀀스 (12bytes = 4+4+4 bytes)
  • 만약 Binary가 필요 없다면 "BATCH_LENGTH"만 JSON에 두고 Binary는 생략해도 됩니다.

 

Batch Table (선택)

  • 각 개별 모델(feature)에 대한 속성값 저장
  • 예: 건물 이름, ID, 색상, 높이 등
  • JSON + Binary로 구성되어 있으며, JSON만 있어도 충분

Batch Table JSON 예시

{
  "name": ["A타워", "B빌딩", "C센터"],
  "height": [55.2, 72.0, 33.5],
  "color": [
    [255, 0, 0],
    [0, 255, 0],
    [0, 0, 255]
  ]
}

이 경우 "BATCH_LENGTH": 3이므로, name, height, color 속성도 각각 3개 모델의 값을 순서대로 나열합니다.
즉, 각 batchId에 따라 속성이 1:1 매핑됩니다.
 

Binary glTF 또는 GLB (* 필수)

  • 실제 3D 모델 데이터 (메시, 재질, 텍스처 등)
  • glTF 또는 GLB 포맷의 바이너리 표현
  • 내부에는 각 메시(mesh)가 batchId attribute(* 필수) 가짐으로써 Batch Table의 속성과 연결됨

glTF structure JSON 예시

{
  "meshes": [
    {
      "primitives": [
        {
          "attributes": {
            "POSITION": 0,
            "NORMAL": 1,
            "_BATCHID": 2
          },
          "indices": 3,
          "material": 0
        }
      ]
    }
  ],
  "accessors": [
    // POSITION
    { "bufferView": 0, "componentType": 5126, "type": "VEC3", "count": 123 },
    // NORMAL
    { "bufferView": 1, "componentType": 5126, "type": "VEC3", "count": 123 },
    // _BATCHID
    { "bufferView": 2, "componentType": 5121, "type": "SCALAR", "count": 123 }
  ]
}

 

glTF structure JSON 예시 [accessors][_BATHCID] 해석

필드 의미
bufferView: 2 2번 버퍼뷰를 참조함 (즉, 전체 Binary 중 일부 영역)
componentType: 5121 값의 자료형: UNSIGNED_BYTE (1바이트 정수)
type: "SCALAR" 단일 값 (벡터가 아님, VEC3는 벡터)
count: 123 총 123개의 데이터가 들어 있음 = 정점(vertex) 123개

즉, 2번 bufferView에서 시작하는 binary 영역을 123개의 UNSIGNED_BYTE (1바이트 정수)로 나누어 읽으며, 각각은 하나의 SCALAR 값(_BATCHID)입니다.

참고: Cesium은 이 _BATHCID 값을 기준으로 Batch Table의 속성을 매핑합니다.

 
그럼 2번 bufferView(_BATCHID)는 어떤식으로 구성될까요?
123개의 1바이트 정수를 가지므로 123개의 바이트 길이를 가진 바이너리 일 것입니다.
 

_BATCHID bufferView(2번) 예시

{
  "bufferViews": [
    ...
    {
      "buffer": 0,
      "byteOffset": 512,
      "byteLength": 123,
      "target": 34962
    }
  ]
}

 

_BATCHID bufferView(2번) 예시 해석

필드 의미
buffer: 0 실제 데이터를 담고 있는 buffer 인덱스
byteOffset: 512 buffer 내에서 이 view가 시작되는 위치 (512바이트 이후)
byteLength: 123 이 view의 길이 (123바이트)
target: 34962 ARRAY_BUFFER, 주로 vertex attribute용

즉, 이 BufferView는 buffer[0]의 512번째 바이트부터 123바이트 구간을 참조합니다.
 

Buffer 예시 - 외부 binary 파일(.bin)을 사용하는 경우

glTF(.gltf) 파일은 실제 geometry 데이터(Position, Normal, Texcoord, _BATCHID 등)를 직접 포함하지 않고, 외부 이진 파일(model.bin)을 참조합니다.

{
  "buffers": [
    {
      "uri": "model.bin",
      "byteLength": 2048
    }
  ]
}

이 경우, model.gltf는 구조를 설명하고, model.bin은 실제 데이터를 담고 있는 별도 파일이며,
model.bin은  2048바이트 길이로 POSITION → NORMAL → TEXCOORD → _BATCHID 순서 등으로 배치되어 있습니다
 

Buffer 예시 - 외부 binary 파일이 없는 경우 (GLB 또는 내장형)

"uri" 필드가 없는 경우, 해당 buffer는 GLB 파일 내부의 BIN chunk에 직접 포함됩니다.
즉, buffer의 이진 데이터는 GLB 파일 안에 함께 내장되어 있으며, GLB의 구조에 따라 아래 위치에서 시작합니다.

GLB
┌────────────┐
│ Header     │ 12 bytes
├────────────┤
│ JSON Chunk │ 구조 정보 (glTF JSON)
├────────────┤
│ BIN Chunk  │ buffer가 저장된 실제 데이터 영역
└────────────┘
BIN chunk의 시작 오프셋은 Header(12Bytes) + JSON chunk 크기 + Padding(보통 4 또는 8byts)을 고려해 계산됩니다.

glTF 뷰어나 파서는 이 구조를 따라 bufferView → accessor → geometry 속성 데이터로 연결해서 해석합니다.
 
정리하면, glTF에서 "buffers"의 "uri"는 이진 데이터를 외부 파일에서 불러올지, 아니면 GLB 내에서 자체 포함할지를 결정하는 중요한 단서입니다. GLB 또는 .b3dm처럼 내장 구조에서는 "uri" 없이 "byteLength"만 지정되며, 실제 데이터는 GLB의 BIN chunk 영역에 포함되어 해석됩니다.
 

실제 Binary 데이터 예시

model.bin 파일 내부는 다음과 같은 구조를 가집니다.

[ 0~511 bytes ]    → POSITION, NORMAL, TEXCOORD 등의 vertex attribute
[512~634 bytes]    → batchId (UNSIGNED_BYTE 123개)
[635~2047 bytes]   → 다른 데이터, index buffer 등

 

batchId 데이터 추출 과정 요약

Accessor → bufferView → buffer 내부의 BATCHID 바이트 구간
                           └───────> UNSIGNED_BYTE 위 예시의 경우 123개 (512~634)

1. 각 bin 파일(model.bin 등)은 glTF structure JSON의 accessor가 참조하는 bufferView를 찾고,
2. 해당 bufferView가 참조하는 buffer의 byteOffset: 512, byteLength: 123를 탐색하여,
3. batchId 데이터만 뽑아 사용할 수 있습니다.


B3DM Padding 정렬 규칙

.b3dm의 각 섹션은 8바이트 정렬(alignment)을 만족해야 합니다.

  • Binary glTF는 반드시 8바이트 경계에서 시작해야 함
  • 이를 위해 Feature Table이나 Batch Table 끝에 패딩(0x00)을 추가
  • 최종 tile.byteLength도 8바이트 정렬이어야 함

요약

- B3DM은 3D Tiles 1.0 포맷으로, 여러 개의 glTF 모델을 하나의 파일로 묶어 렌더링 성능과 스트리밍 효율을 높이기 위해 도입됐습니다.
- 각 모델은 고유한 속성을 가질 수 있으며, Batch Table과 _BATCHID를 통해 속성과 연결됩니다.
- 내부 구조는 Header, Feature Table, Batch Table, Binary glTF로 구성되며, 모든 섹션은 8바이트 정렬을 따라야 합니다.
- 현재는 3D Tiles 1.1에서 glTF 단일 포맷과 EXT_structural_metadata로 통합되면서, B3DM은 레거시 포맷으로 간주되고 있지만 여전히 많은 프로젝트에서 활용되고 있습니다.

 
3D Tiles 1.0 비교

포맷 주 용도 내부 구조
Batched 3D Model (.b3dm) 여러 건물을 하나로 묶어 처리 Feature Table + glTF
Instanced 3D Model (.i3dm) 동일한 모델을 여러 개 배치(가로등, 나무) Feature Table + glTF + instance 정보
Point Cloud (.pnts) 점 단위 스캔 데이터(LiDAR ) Feature Table + Position/Color

 


참고 자료

3D Tiles 공식 스펙 (Cesium)
Batch Table 설명 (Cesium)
 

'Cesium > 3D Tiles Formats' 카테고리의 다른 글

glTF 2.0 구조 및 구성 요소  (3) 2025.04.17
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함