10
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

glTF 2.0 skinning データ構造と評価のメモ

10
Last updated at Posted at 2020-02-03

背景

glTF 2.0 で skinning(キャラクターアニメーションとか)したい.

仕様

skinning = vertex skinning = Linear Blending Skinning(LBS) = Maya でいう skeleton, bone, skinCluster あたりです.
dual quaternion とか, delta mash などの advanced な skinning は含まれていません.

しかし初見すると glTF の skinning の仕組みはまったくよくわかりませんね :cry: :cry:
私自身 skinning の理解をするにはなかなか時間がかかりました(今でも 25% くらいしか理解していませんが... :cry:).

(まず注意事項) skinning つき glTF は DCC のフォーマットとして使うのを考えてはいけない

現在の glTF 2.0 の skinning の定義は再生に特化しており, また厳密な skinning 定義もなく, DCC の skinning(ボーン)データ構造とも異なります.

したがって, Skinning を含んだデータ(特にキャラクターデータ)に対して, DCC(blender, maya など)から glTF に export したり, glTF から DCC(blender, maya)に import したりは考えないほうがいいです.
(複雑なキャラクターになるとだいたいうまくいきません)

glTF はデータ交換のエコシステムと謳っていますが, こと skinning においてはそれは全くの幻想です.

現状の glTF 2.0 の一番の問題が skinning 周りの定義であると言えます
(glTF 全体の方向性とか仕様以外の issue で最も伸びているのが 1665 skinning です)

Stricter Skinning Requirements #1665
https://github.com/KhronosGroup/glTF/issues/1665

一応後述する KHR_skin_strict などで, skinning の仕様を厳密にしたり, 計算方法を詳細に記述するなど提案されていますが, glTF 2.0 の仕様の範囲では運用は難しいと考えられます(glTF 3.0(glTF Next)へ持ち越しになると思われます)

skinning つきデータについては, 大人しく USD(Universal Scene Description)などを使ったほうがよいと思います.
(Blender 2.82 から USD export 対応が始まりました. いずれは USD importer もできるはず?)

(さらに注意事項) skinning 情報からシーングラフのデータは十分に復元できない.

再生に特化しているため, skinning 情報からシーングラフ構造を十分に復元することはできません

inverseBindMatrix は, 実際には任意の行列を定義できるため, かならずしも bind matrix(Maya でいう bind pose matrix でしょうか?)を逆行列にしたものとは限らないからです. bind matrix の情報定義自体は glTF の仕様にありません.

たとえばこのあたりのチュートリアルでは, inverseBindMatrix の逆行列をとっても bind matrix にはなりません.

これは, たとえば自前の描画エンジンとかでちょっと skinning を弄りたいときとかに問題になります.

skeleton の階層とか

[Clarification] Skeleton root and joints hierarchy #1270
https://github.com/KhronosGroup/glTF/issues/1270

Add implementation notes about which transforms apply to skinned meshes #1195
https://github.com/KhronosGroup/glTF/pull/1195

How to bind bones with vertices in skeleton animation? #1320
https://github.com/KhronosGroup/glTF/issues/1320

skeleton プロパティ

ノード階層(joint 階層)のどこを起点とするかの skeleton .
いずれ不要になるかも?

joint

joint 自体は node の行列で表現します. joint(node)は階層構造になっているのが要求されます(glTF のデータ的には階層構造になっていなかったり, 循環参照もできてしまったりする. validator でははそのあたり検出してチェックしてくれるはず)

skinning 行列の計算

jointMatrix(j) =
  globalTransformOfNodeThatTheMeshIsAttachedTo^-1 *
  globalTransformOfJointNode(j) *
  inverseBindMatrixForJoint(j);
  • globalTransformOfNodeThatTheMeshIsAttachedTo : skin が含まれている(つまり mesh も含まれている) node の world 行列. globalTransformOfNodeThatTheMeshIsAttachedTo^-1 はその逆行列.
  • globalTransformOfJointNode(j) : joint の parent node の world 行列 と, joint 自身の node の行列をかけたもの.
  • inverseBindMatrixForJoint は glTF Buffer に別途含まれている joint ごとの行列(Exporter or glTF 生成側で計算して出力されたもの). inverseBindMatrices ではアクセッサのインデックスを指定(基本的には joint の個数ぶんの行列データ配列への buffer(view) の番号なので, 行列の値を直接指定しているわけではなく, わかりずらい).

inverseBindMatrices が定義されていない場合は, bind matrix の逆行列は単位行列とする.

この場合, bind matrix 相当の変換がすでに頂点データもしくは joint node の行列に含まれているとする.

コード例としては, Sascha 先生の Vulkan-glTF-PBR を参考ください.

頂点単位の skinning 処理

jointMatrix を animation などで変更があったときに再計算(通常 CPU)したのち, vertex shader で頂点単位で skinning 計算をします.
(頂点数など少なければ CPU で計算するという手も).

計算自体は行列計算するだけなので, 特に複雑なことはありません.

glTF 上では, 4 個づつ joint/weight 情報が頂点アトリビュートとしてアサインされています(JOINTS_0/WEIGHTS_0)
この 4 個のかたまりを set と読んだりするようです(UV set とおなじような感じでしょうか).
4 個以上の場合は, JOINTS_1/WEIGHTS_1, JOINTS_2/WEIGHTS_2, ... として定義します.

ただ, 既存の glTF ビューアなどでは, 多くの場合 4 個まで(JOINTS_0/WEIGHTS_0)の対応になっています.

weight は, 仕様上は非負かつ正規化(全ての weight の和をとると 1.0)されているとしますが, 実際には 1.0 にならなくともエラーにはなりません(glTF viewer などでは warning を出してくれたりはします).

Are skin weights normalized? #1213
https://github.com/KhronosGroup/glTF/issues/1213

joint 行列をダンプする

RenderDoc などのデバッガでシェーダに渡ってくる jointMatrix の値などが確認できて便利です.

Linux or Android 向け Vulkan アプリのデバッガーのメモ
https://qiita.com/syoyo/items/4f90a015eace55280c90

提案中の skinning 拡張など

厳密な skin 定義をする KHR_skin_strict

提案中です.

skeleton 定義

skeleton の定義をきちんとしようが提案中です.

Extension Proposal regarding Skeleton Definitions in glTF
https://github.com/KhronosGroup/glTF/pull/1695

その他

inverseBindMatrices がバッファーでバイナリなので, 内容の確認や, ノード階層を変えたときなどの修正がやりずらくぴえん :cry: :cry:

animation 関連の値も同様.

glTF のプロパティのいくつかを ASCII で定義する拡張が求められます.

10
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?