天天看點

glb格式解析

GLB是GLTF模型的二進制檔案格式表示。GLTF的node層次結構、mesh、材質、動畫等資訊都用二進制資訊表示。

GLB檔案主要包括Header和Chunks兩部分,檔案結構示意圖如下

glb格式解析

Header

GLB檔案的頭部包含3部分,每部分由4 bytes組成,共12 bytes:

  • unit32 magic - GLTF辨別符,數值為 0x46546C67,gltf的ASCII碼值
  • unit32 version - GLTF版本号
  • unit32 length - GLB檔案的大小,包括header和所有chunks的位元組長度

Chunks

uint32 uint32 ubyte[]
chunkLength chunkType chunkData
  • chunkLength - chunkData的長度
  • chunkType - chunk的類型,主要有JOSN和BIN(對應我們平時的scene.gltf和scene.bin的資料)
  • chunkData - chunk的binary資料

chunk Type

Chunk Type ASCII Description
0x4E4F534A JSON Structured JSON content
0x004E4942 BIN Binary buffer

這裡展示用python加載glb格式到json和bytes位元組(對應gltf的bin檔案)

def __load_glb__(file_name):
    gltf_json = None
    gltf_buffers = []
    with open(file_name, 'rb') as f:
        # glb-header:12-byte
        # uint32 magic - magic equals 0x46546C67. It is ASCII string glTF, and can be used to identify data as Binary glTF
        # uint32 version - indicates the version of Binary glTF container format
        # uin32 length - the total length of the Binary glTF, including Header and all chunks in bytes
        b = f.read(GLB_HEADER_BYTE_LENGTH)
        magic = b[0:4]
        if magic != b'glTF':
            raise RuntimeError('File is not a valid GLB file')
        version, = struct.unpack_from('<I', b, 4)
        if version != 2:
            raise RuntimeError('Unsupported GLB file version: '+str(version)+'. Only version 2 is currently supported')
        byte_len, = struct.unpack_from('<I', b, 8)

        # glb_chunk_array: have 1 json chunk and 0 or 1 bin chunk
        # uint32 chunk_length:length of chunk_data in bytes
        # uint32 chunk_type: json and bin
        # ubyte chunk_data: binary payload of chunk
        # 不使用while,定義最大的循環為1024*1024
        for i in range(1024*1024):
            b = f.read(GLB_CHUNK_HEADER_BYTE_LENGTH)
            if b == b'':
                break
            if len(b) != 8:
                raise RuntimeError('Unexpected EOF when processing GLB chunk header. Chunk header must be 8 bytes')
            chunk_length, = struct.unpack_from('<I', b, 0)
            chunk_type, = struct.unpack_from('<I', b, 4)
            if chunk_length == 0:
                raise RuntimeError('chunk may not be empty')
            chunk_data = f.read(chunk_length)
            if chunk_type == GLB_JSON_CHUNK_TYPE:
                gltf_json = json.loads(chunk_data.decode('utf-8').strip())
            elif chunk_type == GLB_BINARY_CHUNK_TYPE:
                gltf_buffers.append(chunk_data)
            else:
                raise RuntimeError('chunk type error')
    return gltf_json, gltf_buffers