티스토리 뷰

Cesium/3D Tiles Formats

glTF 2.0 구조 및 구성 요소

시뮬레이션 프로그래머 2025. 4. 17. 13:03

개요

glTF (GL Transmission Format)은 3D 콘텐츠의 효율적인 송수신 및 로딩을 위한 표준 파일 포맷입니다. JSON으로 메타데이터를 정의하며, 바이너리(blob) 데이터를 통해 정점, 텍스처, 애니메이션 등의 실질 데이터를 포함합니다.

  • 텍스트(JSON) + 바이너리(Buffer) 구조
  • 파일 포맷:
    • .gltf : JSON + 외부 bin + 외부 texture
    • .glb : JSON + bin + texture를 하나의 바이너리로 내장
⚠️ 주의: glTF 또는 GLB는 3D Tiles 포맷이 아니고, 3D Tiles 의 구성 요소가 될 수는 있습니다.

 

glTF 객체 계층 구조

  • glTF는 JSON 구조로 메타데이터를 표현하고, 바이너리로 실제 데이터(buffer)를 저장합니다.
  • 주요 구성 요소:
    • scene : 렌더링할 장면
    • node : scene을 구성하는 트리 구조의 객체
    • mesh, material, accessor, bufferView, buffer 등

 

glTF 좌표계와 단위

  • 좌표계 y-up 좌표계 입니다.
  • 모든 선형 거리미터(m) 단위입니다.
  • 모든 각도라디안(radian) 단위입니다.
  • 회전 방향: 양의 회전은 시계 반대 방향(counter-clockwise) 입니다.

 

glTF 구성요소 목차

  1. Scene
  2. Node
  3. Transformations (TRS vs Matrix)
  4. Mesh
  5. Primitive
  6. Accessor
  7. BufferView
  8. Buffer
  9. Material
  10. Texture
  11. Extensions

 

Scene

  • glTF 파일에는 0개 이상의 scene 객체가 포함될 수 있습니다.
  • 각 Scene은 최상위 node들의 인덱스를 포함하며, 이 node들을 기준으로 하위 트리가 구성됩니다.
  • scene 키로 기본 렌더링 장면을 지정할 수 있습니다. 지정되지 않으면 명시적으로 요청될 때까지 렌더링되지 않습니다.
  • scene이 없는 glTF 파일은 material, mesh 등 개별 엔터티만으로 사용할 수 있습니다.
  • scene이 명시되지 않은 경우, 요청될 때까지 렌더링이 지연될 수 있습니다.\

Scene 예시

{
  "scene": 0,
  "scenes": [
    {
      "nodes": [0]
    }
  ]
}

예를 들어, 다음 JSON 예제는 인덱스 0번 Scene을 기본 장면으로 지정하며, 해당 Scene은 인덱스 0번 Node를 최상위로 사용합니다.

  • scene: 0 → 0번 Scene 객체가 기본 장면임
  • scenes[0].nodes: [0] → 인덱스 0번 Node를 루트로 삼아 씬을 구성함

이 구조를 통해 glTF 뷰어나 로딩 엔진은 어디서부터 장면을 구성할지 알 수 있습니다.

 

Node

  • Scene을 구성하는 기본 단위입니다.
  • 부모-자식 관계를 형성하며 트리 구조를 형성합니다.
  • 각 Node는 다음 항목을 가질 수 있습니다:
    • matrix 또는 TRS(translation, rotation, scale) 변환 속성
    • children: 하위 노드 인덱스 배열
    • mesh: 연결된 메시 인덱스
    • camera, skin, light 등의 다른 요소

⚠️ 제약 조건:

  • Node 계층 구조는 반드시 순환(circular reference) 없이 엄격한 트리(strict tree) 형태를 가져야 합니다.
    • 즉, 한 노드는 부모를 0개 또는 1개만 가질 수 있습니다.

Node 예시

{
  "nodes": [
    {
      "name": "Root",
      "children": [1, 2],
      "translation": [0, 0, 0]
    },
    { "name": "Mesh_A", "mesh": 0 },
    { "name": "Mesh_B", "mesh": 1 }
  ]
}

 

Transformations (TRS vs Matrix)

선택 1: matrix

4x4 행렬로 위치, 회전, 스케일을 한 번에 표현

"matrix": [1, 0, 0, 0,
           0, 1, 0, 0,
           0, 0, 1, 0,
           0, 0, 0, 1]

 

선택 2: TRS

독립적인 위치, 회전, 스케일 요소로 표현

"translation": [1, 1, 1],
"rotation": [0, 0, 0, 1],
"scale": [1, 1, 1]

rotation은 단위 사원수(quaternion)로 표현되며, [x, y, z, w] 구조입니다.

 

Mesh

  • 실제로 렌더링될 정점 정보와 형태를 정의
  • 하나의 mesh는 하나 이상의 primitive 배열을 가짐
  • 각 primitive는 하나의 material과 정점 속성 집합을 가짐

Mesh 예시

{
  "meshes": [
    {
      "primitives": [
        {
          "attributes": {
            "POSITION": 0,
            "NORMAL": 1,
            "TEXCOORD_0": 2
          },
          "indices": 3,
          "material": 0
        }
      ]
    }
  ]
}

 

Mesh 예시 의미:

  • meshes[0] 은 하나의 메시 객체입니다.
  • 이 메시에는 primitives 배열이 하나 포함되어 있고, 이 배열에는 렌더링 단위인 하나의 primitive 객체가 정의되어 있습니다.
  • attributes는 정점 속성을 가리킵니다. POSITION, NORMAL, TEXCOORD_0 은 각각 위치, 법선, 텍스처 좌표이며**, 0~2번 accessor를 통해 데이터를 참조**합니다.
  • indices는 삼각형 인덱스를 담은 accessor를 의미하며, 정점 순서 재사용을 위해 3번 accessor를 참조합니다.
  • material: 0 은 이 primitive가 materials[0] 배열의 첫 번째 재질(Material) 을 사용함을 의미합니다.

 

Primitive

  • Primitive는 메시를 구성하는 렌더링 최소 단위(position, normal, material, topology 등)입니다.
  • 하나의 메시(mesh) 안에는 여러 primitive가 있을 수 있으며, 이들은 보통 다른 재질이나 정점 속성을 갖는 하위 조각으로 사용됩니다.
  • 각 primitive는 하나의 재질(material)만 적용할 수 있으며, 하나의 정점 집합과 하나의 인덱스 집합으로 구성됩니다.
  • GPU는 각 primitive 단위로 렌더링을 수행합니다.
  • 정점 속성은 accessor를 통해 연결됨
  • 각 primitive에는 mode라는 속성이 있으며, 이는 해당 primitive가 어떤 도형 방식으로 렌더링되는지를 정의합니다. 기본값은 4 (TRIANGLES)입니다.

mode 의미

0 POINTS
1 LINES
2 LINE_LOOP
3 LINE_STRIP
4 TRIANGLES (기본값)
5 TRIANGLE_STRIP
6 TRIANGLE_FAN

 

Mesh를 구성하는 Primitive 예시

{
  "meshes": [
    {
      "primitives": [
        {
          "attributes": {
            "POSITION": 0,
            "NORMAL": 1,
            "TEXCOORD_0": 2
          },
          "indices": 3,
          "material": 0,
          "mode": 4 // (기본 값)
        }
      ]
    }
  ]
}

 

Mesh를 구성하는 Primitive 예시 의미:

  • attributes 객체의 각 키(POSITION, NORMAL, TEXCOORD_0)는 정점 속성의 종류를 의미하며,
  • 각 값(0, 1, 2)은 accessors 배열의 인덱스를 의미합니다. 예: "POSITION": 0 → accessors[0] 사용.
  • 해당 accessor는 실제 데이터를 담고 있는 bufferView를 가리키고, 이 bufferView는 다시 buffer로 연결됩니다.
  • 즉, 이 숫자는 데이터를 해석하는 경로를 연결해주는 인덱스입니다.

 

Accessor

  • bufferView의 바이너리 데이터를 특정 형식으로 해석하기 위한 메타정보를 포함합니다.
  • type, componentType, count, min, max 등의 메타정보를 포함

필드 설명

bufferView 참조할 BufferView 인덱스 (필수)
byteOffset bufferView 내에서 데이터가 시작되는 바이트 위치 (기본값: 0)
componentType 각 요소의 자료형을 정의하는 열거값 (예: 5126은 float)
count 요소 개수 (벡터/행렬 단위)
type 요소의 구조 (예: VEC3, SCALAR)
min, max AABB용 최소/최대 값 (POSITION에 주로 사용)
sparse 희소 데이터 표현 시 사용되는 구조 (선택)
name accessor의 이름 (선택)

 

component Type 유형

값 의미 크기(bytes)

5120 BYTE (int8) 1
5121 UNSIGNED_BYTE (uint8) 1
5122 SHORT (int16) 2
5123 UNSIGNED_SHORT (uint16) 2
5125 UNSIGNED_INT (uint32) 4
5126 FLOAT (float32) 4

 

type 유형

값 요소 수 예시

SCALAR 1 float, int 등 단일 값
VEC2 2 텍스처 좌표 등
VEC3 3 정점 위치, 법선 등
VEC4 4 사원수 회전, 색상 등
MAT2 4 2x2 행렬
MAT3 9 3x3 행렬
MAT4 16 4x4 행렬

 

Accessor 예시

{
  "accessors": [
    {
      "bufferView": 0,
      "componentType": 5126,
      "count": 1024,
      "type": "VEC3",
      "min": [-1.0, -1.0, -1.0],
      "max": [1.0, 1.0, 1.0]
    }
  ]
}

 

Buffer Views

BufferView는 Buffer 내 특정 바이트 구간을 정의하여, 그 구간을 Accessor 또는 이미지와 같은 객체가 사용할 수 있습니다.

  • BufferView는 반드시 하나의 목적(정점 속성, 인덱스, 이미지 등)에만 사용되어야 합니다.
  • byteOffset과 byteLength로 버퍼 내 영역을 정의합니다.
    • 구조: Buffer(참고), byteOffset, byteLength, byteStride, target
  • target은 이 뷰가 어떤 용도로 사용되는지를 지정하며, WebGL의 바인딩 상수를 따릅니다.
    • 34962: 정점 속성용 ARRAY_BUFFER
    • 34963: 인덱스용 ELEMENT_ARRAY_BUFFER

Buffer Views 예시

{
  "bufferViews": [
    {
      "buffer": 0,
      "byteLength": 25272,
      "byteOffset": 0,
      "target": 34963    // ELEMENT_ARRAY_BUFFER (인덱스)
    },
    {
      "buffer": 0,
      "byteLength": 76768,
      "byteOffset": 25272,
      "byteStride": 32,
      "target": 34962    // ARRAY_BUFFER (정점)
    }
  ]
}

 

 

target 값 의미

34963 ELEMENT_ARRAY_BUFFER (Index Buffer)
34962 ARRAY_BUFFER (Vertex Attributes)

 

Buffer

Buffer는 실제 바이너리 데이터(blob)를 저장하는 컨테이너입니다.

  • 구조: byteLength, uri (또는 GLB 내장)
  • 외부 파일 경로로 지정하거나 base64 URI 또는 GLB 바이너리 청크로 내장 가능
  • 버퍼는 다음을 저장할 수 있습니다:
    • 정점 속성(Vertex Attributes)
    • 인덱스(Index Buffer)
    • 애니메이션 데이터
    • 스킨(Skinning) 데이터
    • 이미지 데이터

Buffer 예시

{
   "buffers": [
       {
           "byteLength": 102040,
           "uri": "car.bin"
       }
   ]
}
  • byteLength: 버퍼 데이터의 총 바이트 크기
  • 참고: 예시의 102040은 BufferViews에서 바이트의 총 길이가 102040 = 25752(offset) + 76768(length)
  • uri: 외부 파일 또는 Base64 인코딩

⚠️ GLB 파일 포맷에서는 버퍼가 바이너리 청크로 내장되며, 크기는 최대 $(2^{32} - 1)$ 바이트입니다.

 

⚠️ 버퍼와 버퍼 뷰 주의 사항

  • 모든 버퍼 데이터는 반드시 리틀 엔디안(little-endian) 방식으로 저장해야 합니다.
  • bufferView는 정점 속성정점 인덱스같은 뷰로 공유할 수 없습니다.
  • data URI를 사용할 경우, mediatype은 application/octet-stream 또는 application/gltf-buffer로 지정해야 합니다.

 

Material

  • 메시 표면의 시각 효과를 정의하는 재질 정보입니다.
  • glTF는 PBR 기반 재질(pbrMetallicRoughness)을 사용합니다.
  • 주요 속성:
    • baseColorFactor: 기본 색상 (RGBA)
    • metallicFactor: 금속성 (0.0~1.0)
    • roughnessFactor: 거칠기 (0.0~1.0)
    • baseColorTexture: 텍스처 이미지 참조
    • normalTexture: 법선 맵

Material 예시

{
  "materials": [
    {
      "pbrMetallicRoughness": {
        "baseColorFactor": [1.0, 0.5, 0.5, 1.0],
        "metallicFactor": 0.1,
        "roughnessFactor": 0.9,
        "baseColorTexture": {
          "index": 0
        }
      },
      "normalTexture": {
        "index": 1
      }
    }
  ]
}

 

Material 예시 의미:

  • "baseColorTexture": { "index": 0 }는 textures[0] 항목을 참조합니다. 해당 텍스처는 일반적으로 이미지와 샘플러와 연결되어 있으며, 재질 표면의 컬러 표현에 사용됩니다.
  • 마찬가지로 "normalTexture": { "index": 1 }는 textures[1]를 참조하여 노멀맵을 적용합니다.

 

Texture

  • 텍스처는 이미지(images)와 샘플러(samplers)를 조합하여 텍스처 정보를 구성합니다.
  • textures[n]의 source 필드는 사용할 이미지 인덱스를 가리키고,
  • sampler는 텍스처의 필터링과 래핑 방법을 지정합니다.

속성 설명

source 이미지 인덱스 (images[n])
sampler 샘플러 인덱스 (samplers[n])

 

Texture 예시

{
  "textures": [
    {
      "source": 0,
      "sampler": 0
    }
  ]
}

해당 텍스처는 이후 material.pbrMetallicRoughness.baseColorTexture.index에서 참조되어 메시의 표면에 적용됩니다.

 

Extensions

  • glTF는 확장성 있는 구조를 제공하며, 추가 기능은 extensionsUsed 또는 extensionsRequired에 명시합니.
  • 확장 이름은 보통 KHR_(공식 Khronos 확장), EXT_(비공식 확장) 등의 접두어를 가집니다.

Extensions 유형

KHR_draco_mesh_compression 메시 데이터 압축을 위한 Draco 지원
EXT_meshopt_compression MeshOptimizer 기반 압축 포맷 지원
KHR_lights_punctual 직관적인 광원 모델(점, 방향, 스포트 조명)
KHR_materials_unlit 비조명(Unlit) 머티리얼 표현 지원
KHR_texture_transform 텍스처 오프셋, 회전, 스케일 조정 지원

 

Extensions 예시

{
  "extensionsUsed": ["KHR_draco_mesh_compression"],
  "extensionsRequired": ["KHR_draco_mesh_compression"]
}

확장 기능이 사용된 경우, 해당 extension 객체가 메시, 머티리얼, 노드 등 특정 요소 내부에 extensions 필드로 삽입됩니다.

 

Extensions을 Mesh에 적용한 예시

"meshes": [
	{
	    "primitives": [
	        {
	            "attributes": {
	                "POSITION": 1,
	                "TEXCOORD_0": 2,
	                "_FEATURE_ID_0": 3
	            },
	            "mode": 4,
	            "material": 0,
	            "indices": 0,
	            "extensions": {
	                "KHR_draco_mesh_compression": {
	                    "bufferView": 2,
	                    "attributes": {
	                        "POSITION": 0,
	                        "TEXCOORD_0": 1,
	                        "_FEATURE_ID_0": 2
	                    }
	                },
	                "EXT_mesh_features": {
	                    "featureIds": [
	                        {
	                            "featureCount": 52,
	                            "attribute": 0,
	                            "propertyTable": 0
	                        }
	                    ]
	                }
	            }
	        }
	    ]
	}
],

 

 

참고

https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html

https://cesium.com/blog/2022/10/05/tour-of-the-new-gltf-architecture-in-cesiumjs/

 

 

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

3D Tiles 1.0 주요 포맷 정리: B3DM  (1) 2025.04.20
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
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
글 보관함