glTF 覚え書き

公開:2021/02/23
更新:2021/02/23
4 min読了の目安(約3900字TECH技術記事

最近 glTF のコンバータを書いたので,少しまとめておきます.
あくまで備忘録のような内容なので,悪しからず.

📌 フォーマットについて

📌 ツール

📌 エクスポータ/インポータ

📌 コンバータ

📌 その他

  • JsonGrid - glTF の中身を見るのに便利な JSON ビューア
  • GltfBrowser - こちらも glTF の中身を解析できるビューア.公式のサンプルデータを手軽に確認できます.3D ビューアも内蔵されていて便利です.

📌 クイックリファレンス

glTF の公式サイトにはチートシートがあって,有志が日本語版を公開してくれています.このチートシートはわかりやすいのですが,入門という感じで,リファレンスとしては情報が不足しています.公式サイトに完全な仕様があるので,そちらを参照してもいいのですが,手元にあると便利なクリックリファレンス的なものが欲しかったので作成しました.

glTF2_QuickRef_jp

pdf 版や最新版は以下の場所にあります.

📌 アニメーション

  • ノードの TRS および,モーフィング用のウェイトのみ対応
  • 将来的にはマテリアルなど他のパラメータに対しても対応できるようになるらしい
  • マトリクスのアニメーションは対応していない
  • マテリアル関連はまだまだ仕様が固まっていない感じ(個人的な意見)

📌 accessor, bufferView, buffer

glTF を扱う上でこの3つが重要.最終的にデータは accessorsbufferViews の配列サイズが巨大になる.インターリーブ形式を上手くつかえば bufferViews の数は抑えられますが,上手くいった試しがありません.

buffer

バイナリデータ.バイナリデータは base64 形式で埋め込むことが出来るし,バイナリファイルとして別のファイルにすることもできる.buffer ごとにバイナリファイルを別々にすることも可能.

bufferView

1つの buffer を参照し,どの場所からどれくらいのサイズをマッピングするかを指定します.参照したデータは頂点データ用(ELEMENT_BUFFER)か,描画インデックス用(ELEMENT_ARRAY_BUFFER),それ以外かも指定します.インターリーブデータを扱うためのストライドもここで指定します.

accessor

1つの bufferView を参照し,そこにどのような要素が,いくつ格納されているかを指定します.例えば componentTypeVEC3 とし,type5126count100 とすると,bufferView で指定した場所には3次元ベクトルの浮動小数点データが100個配置されていることになります.

📌 スキンアニメーション

glTF の単純なモデルの解説は多いので,ここではスキンアニメーションに関することをまとめておきます.

頂点データにジョイントインデックスとウェイト値を含める

primitiveattributes にジョイントインデックス JOINTS と ウェイト値 WEIGHTS が必要です.JOINTSWEIGHTS はセマンティクスと呼ばれ,1つの頂点データに同じセマンティクスのデータを複数入れることができます.これはセマンティクス名の後ろにインデックスを追加して指定します.例えば JOINTS_0WEIGHTS_0 などです.ちなみに TEXCOORD_0COLOR_0 といったテクスチャ座標,カラーにも指定することが出来ます.ジョイントインデックスやウェイト値は1つのインデックスで4つのデータを持ちます.glTF ではそれぞれ指定できる型が限られています.

semantics 指定できる型
JOINTS 5121 (UNSIGNED BYTE), 5123 (UNSIGNED SHORT)
WEIGHTS 5126 (FLOAT), 5121 (UNSIGNED BYTE) normalized, 5123 (UNSIGNED SHORT) normalized

一般的には JOINTSUNSIGNED SHORTWEIGHTS には FLOAT が使われていると思います.

skins

skins には骨構造を記述します.逆バインド行列 inverseBindMatrices,ジョイント配列 joints ,骨構造のルートノード skeleton を設定します.

"skins": [{
    "inverseBindMatrices": (index of accessors),
    "joints" : [ (index of nodes)...],
    "skeleton": (index of nodes)
}]

このデータは node から skin で参照されます.

"nodes": [{
  "mesh": (index of meshes),
  "skin": (index of skins)
  ...
}]

animations

animations には channelssamplers があります.

"animations": [{
  "channels": [...],
  "samplers": [...]
}]

channels ではアニメーション対象 target と,適用するアニメーションのキー情報 samplers を指定します.targetnode で対象となるノードを,path で変更する値の種類を,sampler で,キー情報の参照を指定します.

{
  "channels": [{
    "target": {
      "node": (index of nodes),
      "path": "translation", "rotation", "scale" or "weights"
    },
    "sampler": (index of samplers")
  }]
}

samplers にはアニメーションのキー情報を指定します.input ではキーフレーム時間(秒),output ではキーフレーム値,interpolation では補間方法を指定します.

{
  "samplers": [{
    "input": (index of accessors),
    "output": (index of accessors),
    "interpolation": "LINEAR", "STEP" or "CUBICSPLINE"
  }]
}