About GLTF
Mon, Apr 16, 2018glTF is a 3D format created by Khronos Group, which is developing openGL specifications. glTF 2.0 was released in 2017. VRM is based on glTF 2.0.
What kind of information can be recorded by glTF?
- Mesh (Vertex array、index array)
- Morph target
- Skinning (4weight)
- Texture
- Material (PBR)
- Scene
- Animation1
- Camera1
- Light source1
An entire 3D scene can be recorded.
- OpenGL right-handed, Y-UP coordinate system
- Meter (unit)
- Little endian
glTF format outline
glTF format comprises two parts: a JSON scene description part and a binary part that records images and vertex arrays. External binary data can be accessed by referencing Url or path. For glb format, it combines a JSON part and a binary part into one file. The binary data can be accessed via the offset into the buffer (byteOffset). For a program, it is easier to handle the glb format which is no need to access external files2.
glb format
A structure that hasHeader part + Chunk parts
.
More specifically, it isHeader part + JSON CHUNk + BINARY CHUNK
.
Header part
Length | Content | Type | Value |
---|---|---|---|
4 | ascii | “glTF” | |
4 | glTF version | int32 | 2 |
4 | file size | int32 |
Chunk part
Length | Content | Type | Value |
---|---|---|---|
4 | chunk size | int32 | |
4 | chunk type | ascii | “JSON” or “BIN\x00” |
chunk size | chunk body | byte array |
Example of parsing with python3
import struct
import json
class Reader:
def __init__(self, data: bytes)->None:
self.data = data
self.pos = 0
def read_str(self, size):
result = self.data[self.pos: self.pos + size]
self.pos += size
return result.strip()
def read(self, size):
result = self.data[self.pos: self.pos + size]
self.pos += size
return result
def read_uint(self):
result = struct.unpack('I', self.data[self.pos:self.pos + 4])[0]
self.pos += 4
return result
def parse_glb(data: bytes):
reader = Reader(data)
magic = reader.read_str(4)
if magic != b'glTF':
raise Exception(f'magic not found: #{magic}')
version = reader.read_uint()
if version != 2:
raise Exception(f'version:#{version} is not 2')
size = reader.read_uint()
size -= 12
json_str = None
body = None
while size > 0:
#print(size)
chunk_size = reader.read_uint()
size -= 4
chunk_type = reader.read_str(4)
size -= 4
chunk_data = reader.read(chunk_size)
size -= chunk_size
if chunk_type == b'BIN\x00':
body = chunk_data
elif chunk_type == b'JSON':
json_str = chunk_data
else:
raise Exception(f'unknown chunk_type: {chunk_type}')
return json.loads(json_str), body
with open('AliciaSolid.vrm', 'rb') as f:
parsed, body = parse_glb(f.read())
VRM extension
Information of VRM extension is stored injson['extensions']['VRM']
.