티스토리 뷰
개요
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 구성요소 목차
- Scene
- Node
- Transformations (TRS vs Matrix)
- Mesh
- Primitive
- Accessor
- BufferView
- Buffer
- Material
- Texture
- 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
- user space
- gltf
- high-low encoding
- event srource
- gpu rte dsfun90
- transferto()
- 3d tiles
- relative to eye
- parallel operation
- sendfile()
- relative to center
- kernel space
- append only
- ear clipping
- reciprocal approximation
- cpu i/o
- ear cut
- 병렬 연산
- 삼각분할
- * to glb
- .b3dm
- zero-copy
- * to gltf
- the unix timesharing system
- 3d tiles 1.0
- b3dm to glb
- event streaming
- 역수 근사
- b3dm
- Kafka
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |