glTF 2.0 のすべての標準プロパティを雑に眺める（ついでに .glb の構造も）

glTF 2.0 ファイルの全体像をさらっと把握できるような資料が見つからないので、個人的に調べたメモをここに貼っておきます。

いくらかの前提知識がある方は、プロパティ名を見るだけでも現状の glTF （のコア機能だけ）で何ができるのかの見当をつけられるのかなと思います。

## glTF 2.0 の仕様書

このメモ記事は表層をながめるだけですので、その後は仕様書を見てください：

https://github.com/KhronosGroup/glTF/tree/main/specification/2.0

**追記：** コメント欄にて、公式の概要図を日本語訳されている方の記事を紹介して頂きました：

https://qiita.com/randall2835/items/ec911cb6b0f10677559b

## エンコード方式

glTFでは、シーンや各種オブジェクトの定義は全般的にJSONで記述し、頂点データなどのいわゆる「バッファ」部をバイナリで格納します。これらを最終的にどのようにエンコードするかについて、いくつかの選択肢が用意されています。

- .**gltf (JSON) + .bin (Binary buffer) (+ 画像ファイル)**
    - JSON部分とバイナリ部分を分ける方法。バイナリ部分は複数個に分けてもいい。
    - テクスチャは別途の画像ファイルにもできるし、Binary bufferに含めることもできる。
    - **バイナリ部分を .gltf (JSON) にまとめることも可能**
        - Binary buffer を Data URI scheme を使って uri につっこめばいい。例）`uri="data:application/octet-stream;base64,xxxxxxxxxxxxxxx`
- **.glb (すべて1つのバイナリに固める)**
    - 1つの .glb (バイナリファイル) のみで表現する。
    - ごく単純なヘッダと、JSONチャンクと、Binary bufferチャンクをほぼそのままくっつけたようなシンプルな形式。構造は後述。

## JSON部分の内容

### 注意

以下のJSONの構造の説明では省略していますが、JSONのすべてのオブジェクト階層に以下のデータを持たせることができます。

- `extensions`
    - glTFの拡張機能を使った記述を行う。あらゆるオブジェクトに持たせられる。
- `extras`
    - ユーザ定義の任意データ。あらゆるオブジェクトに持たせられる。

### glTFの構造

以下、注意事項 (TODO):

- 型情報などはもう少し正確にしたいです
- どれが必須 (required) な属性かは示して（示せて）いないです

#### 拡張まわり

- `extensionsRequired` — このアセットを扱う際の必須の拡張機能を列挙する
- `extensionsUsed` — このアセットで使う拡張機能を列挙する

#### メタデータ

- `asset`
    - `version`: “2.0”
    - `generator`: string
    - `copyright`: string
    - `minVersion`: string

#### シーングラフ周り

- `scene`: Id — デフォルトシーンID
- `scenes`: []Scene
    - `name`: string
    - `nodes`: []Id — Nodesのうち root nodes を列挙する
- `nodes`: []node
    - `name`: string
    - `children`: []Id
    - `mesh`: Id
    - `camera`: Id
    - `skin`: Id
    - `matrix`: [16]number
    - `rotation`: [4]number — 回転用のquaternion
    - `translation`: [3]number
    - `scale`: [3]number
    - `weights`: []Id — instantiated morph targets 用の weights。targets数ぶん必要
    - `extensions` (KHR_* などのみ示す)
      - [EXT_mesh_gpu_instancing](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_mesh_gpu_instancing)

#### オブジェクト

- `meshes`: []Mesh — メッシュ
    - `name`: string
    - `primitives` ([]Primitive)
        - `attributes` — 頂点データのaccessor
            - POSITION: Id
            - TEXCOORD_n: Id
            - COLOR_n: Id
            - NORMAL: Id
            - TANGENT: Id
            - JOINTS_n: Id
            - WEIGHTS_n: Id
            - （↑これらはOpenGLでの慣習が元になっているが、glTFでは仕様で定められた名前である）
            - その他のカスタム属性も許される。
        - `indices`: Id — 頂点インデクスのaccessor。指定しない場合はnon-indexed verticesとして解釈する。
        - `material`: Id
        - `mode` — 0 (POINTS), 1 (LINES), 2 (LINE_LOOP), 3 (LINE_STRIP), 4 (TRIANGLES), 5 (TRIANGLE_STRIP), 6 (TRIANGLE_FAN)
        - `targets` — morph targets
            - POSITION: Id
            - TEXCOORD_n: Id
            - NORMAL: Id
            - etc.
        - `extensions` (KHR_* などのみ示す)
            - [KHR_mesh_quantization](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_mesh_quantization)
            - [KHR_draco_mesh_compression](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_draco_mesh_compression/README.md)
    - `weights` — morph targets 用の weights。targets数ぶん必要
- `skins` ([]Skin) — スキニングを実現するための joints とinverse-bind matrices (IBM)
    - `name`
    - `skeleton` — skeleton root として使うnode
    - `joints` — joint として使われる nodes のリスト
    - `inverseBindMatrices` — inverse-bind 行列 (IBM) として使う 4x4行列へのaccessor。IBMは joints 分必要。
- `cameras` ([]Camera)
    - `type` — perspective or orthographic
    - `orthographic`
        - `xmag`: 1
        - `ymag`: 1
        - `zfar`: 100
        - `znear`: 0.01
    - `perspective`
        - `aspectRatio`: 1,
        - `yfov`: 0.7853981633974483,
        - `zfar`: 100,
        - `znear`: 0.01,

ライト（拡張）：

- `extensions` (KHR_* のみ示す)
    - [KHR_lights_punctual](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual/README.md)
    - [EXT_lights_image_based](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_lights_image_based)
    - [EXT_lights_ies](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_lights_ies)

#### アニメーション

- `animations` ([]Animation)
    - `name`
    - `channels`
        - `sampler`: Id
        - `target` — アニメーションで変化させる対象。現状はnodeのTRSとweightsのみ制御できる。
            - `node`: Id
            - `path`: “translation” | “rotation” | “scale” | “weights”
    - `samplers` ([]sampler)
        - `input`: Id — キーフレームタイムスタンプの列 (float Scalar) を表す accessor の Id
        - `output`: Id — 各タイムスタンプでの出力値を表す accessor の Id
        - `interpolation`: “LINEAR” | “STEP” | “CUBICSPLINE”

#### マテリアル

- `materials` ([]Material)
    - `name`
    - `doubleSided`: bool — 両面を表示する（back-face culling を無効化する）かどうか。
    - `pbrMetallicRoughness`
        - `baseColorFactor`
        - `metallicFactor`
        - `roughnessFactor`
        - `baseColorTexture`
            - `index`: Id
            - `texCoord`: integer (TEXCOORD_n の n を指定)
        - `metallicRoughnessTexture`
            - `index`: Id
            - `texCoord`: integer (TEXCOORD_n の n を指定)
    - `alphaCutOff`
    - `alphaMode`: “OPAQUE” | “MASK” | “BLEND”
    - `emissiveFactor`
    - `emissiveTexture`
        - `index`
        - `texCoord`: integer (TEXCOORD_n の n を指定)
    - `normalTexture` — 法線マッピング用
        - `index`
        - `texCoord`: integer (TEXCOORD_n の n を指定)
        - `scale`
    - `occulusionTexture` — オクルージョンマッピング用
        - `index`
        - `texCoord`: integer (TEXCOORD_n の n を指定)
        - `strength`
        - `scale`
    - `extensions` (KHR_* などのみ示す)
        - [KHR_materials_clearcoat](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md)
        - [KHR_materials_emissive_strength](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_emissive_strength/README.md)
        - [KHR_materials_ior](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_ior/README.md)
        - [KHR_materials_iridescence](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_iridescence/README.md)
        - [KHR_materials_sheen](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_sheen/README.md)
        - [KHR_materials_specular](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_specular/README.md)
        - [KHR_materials_transmission](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_transmission/README.md)
        - [KHR_materials_unlit](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_unlit/README.md)
        - [KHR_materials_variants](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_variants/README.md)
        - [KHR_materials_volume](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_volume/README.md)
        - [KHR_texture_transform](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_texture_transform/README.md)

#### テクスチャ

- `textures` ([]Texture)
    - `name`
    - `source`: Id — image
    - `sampler`: Id — sampler
    - `extensions` (KHR_* などのみ示す)
        - [KHR_texture_basisu](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_texture_basisu/README.md)
- `images` — 画像
    - `name`
    - `uri` — 相対パスまたはData URI
    - `bufferView`: Id — バッファを参照することも可能
    - `mimeType` — “image/jpeg” など
- `samplers` ([]sampler) — テクスチャのフィルタやwrappingなどを設定
    - `magFilter`
    - `minFilter`
    - `wrapS`
    - `wrapT`

#### バイナリバッファ

- `accessors` — bufferView をどう見るか。
    - `name`
    - `bufferView`: Id
    - `componentType`: 5120 (BYTE) | 5121 (UNSIGNED_BYTE) | 5122 (SHORT) | 5123 (UNSIGNED_SHORT) | 5125 (UNSIGNED_INT) | 5126 (FLOAT) — 要素の型
    - `count` — 要素数
    - `max`: []number
    - `min`: []number
    - `type`: “SCALAR” | “VEC2” | “VEC3” | “VEC4” | “MAT2” | “MAT3” | “MAT4”
    - `sparse` — bufferをインデクスでアクセスするaccessorも作れる
        - `count`: integer
        - `indices`
            - `bufferView`
            - `byteOffset`
            - `componentType`
        - `values`
            - `bufferView`
            - `byteOffset`
    - `normalized` — 整数型の値を [0, 1] ないしは [-1, 1] に正規化して扱うべきかを示す。
    - `byteOffset`: integer — bufferViewの先頭からのオフセット
- `bufferViews` — バッファの一部分への参照
    - `buffer`: Id
    - `byteLength`: integer
    - `byteOffset`: integer
    - `target`: 34962 (ARRAY_BUFFER) または 34963 (ELEMENT_ARRAY_BUFFER)
    - `extensions`
      - [EXT_meshopt_compression](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_meshopt_compression)
- `buffers` — 実バイナリバッファの参照 (uri)
    - `byteLength`: integer
    - `uri`: string — .bin データへのパス、または Data URI scheme でのバイナリ埋め込み

#### その他の `extensions` (KHR_* のみ示す)：
 - [KHR_xmp_json_ld](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_xmp_json_ld/README.md)

## glTF を glb (バイナリ) でエンコードする場合の形式

とてもシンプル。先頭のヘッダ部に続いて、JSONチャンクとBINチャンクが配置されるだけ。アライメント用のパディングに若干注意。

### ヘッダ

| フィールド | 型 | 説明 |
| --- | --- | --- |
| magic | uint32 | 0x46546C67 (`'glTF'`) |
| version | uint32 | 2 |
| length | uint32 | このglbファイルのサイズ |

### 各チャンク


| フィールド | 型 | 説明 |
| --- | --- | --- |
| chunkLength | uint32 | このチャンクの chunkData のサイズ |
| chunkType | uint32 | `'JSON'` or `'BIN\x00'` |
| chunkData | [chunkLength]byte | データ本体（パディングについての注意あり） |

パディングについての注意。chunkData は、長さが 4 bytes の倍数にアライメントされるように末尾にパディングを入れなければならない。JSONチャンクでは空白文字 (0x20) をパディングとして使い、BINチャンクでは 0x00 をパディングとして使う。 

チャンクは次の2種類のみ：

- Structured JSON Content（1個）
    - データはJSONをそのまま (utf-8) 格納
- Binary buffer（1個または0個）