VRMのドキュメントは https://vrm.dev/に移動しました。

VRM - humanoid 3d avatar format for VR
  •  About GLTF(en)
  • GLTFについて

    glTFはOpenGLの仕様策定をしているKHRONOSによる3Dフォーマットです。2017年にVersion2が策定されました。 VRMはglTF2.0をベースとしたフォーマットとなっています。

    glTFはどんな情報を記録できるのか

    • メッシュ(頂点配列、インデックス配列)
      • モーフターゲット
      • スキニング(4weight)
    • テクスチャ
    • マテリアル(PBR)
    • シーン
    • アニメーション1
    • カメラ1
    • 光源1

    3Dのシーン全体を記録できます。

    • OpenGLの右手系Y-UP座標
    • メートル単位
    • リトルエンディアン

    glTFフォーマット概説

    JSON記述部と、画像や頂点配列を記録するバイナリ部の2つの部分からなります。

    gltf形式では、URLやパスで参照する方法で外部のバイナリデータにアクセスします。 glb形式ではJSON部とバイナリ部をひとつのファイルにまとめていて、バイト列のオフセットでバイナリデータにアクセスします。 プログラムから扱うには外部ファイルへのアクセスが無いglb形式の方が簡単2です。

    glb形式

    ヘッダ部 + チャンク部繰り返しという構造になっています。 実質的には、 ヘッダ部 + JSON CHUNk + BINARY CHUNKとなります。

    ヘッダ部

    長さ 内容
    4 ascii “glTF”
    4 gltfバージョン int32 2
    4 file size int32

    チャンク部

    長さ 内容
    4 chunk size int32
    4 chunk type ascii “JSON” or “BIN\x00”
    chunk size chunk body バイト列

    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による拡張情報

    JSONのjson['extensions']['VRM']以下に格納されています。


    1. VRMではサポートしていません ↩︎ ↩︎ ↩︎

    2. VRMではglbを採用しています。 ↩︎

    VRM - humanoid 3d avatar format for VR