2
1

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 1 year has passed since last update.

UsdSkel のメモ

Last updated at Posted at 2021-05-25

背景

USDZ で AR データのアニメーション(excludes timeSamples)を極めたい.

UsdSkel

機能としては

  • (vertex) skinning
  • blendshape
  • binding

の 3 つっぽい.

skinning と blendshape については, 大まかには glTF や Maya でのそれ(skinning, blendshape)と同じと考えられる.

binding は Maya でいうポーズバインドでしょうかね.
(glTF には対応するものは (explicitly には) ない気がする)

Schema

および USD のソースコードに schema 定義があります.
ただ, schema 自体はあまり参考にならないかもです.

参考情報

:pray:

記述

SkelRoot と Mesh に

prepend apiSchemas = ["SkelBindingAPI"]

を指定する必要があります.
Mesh 側では

  • rel skel:skeleton : 対応する Skeleton への参照(relation)
  • int[] primvars:skel:jointIndices : Joint のインデックス
  • float[] primvars:skel:jointWeight : Skin weight
  • matrix4d primvars:skel:geomBindTransform : Bind transform

あたりが使えるようになります.

頂点あたりの joint/weight の数は Attribute のメタ情報の elementSize で指定します(のはず)

int[] primvars:skel:jointIndices = [...] (
   elementSize = 2
   interpolation = "vertex"
)

Skinning

いわゆる linear blend skinning(Vertex skinning, Maya でいう skinCluster)に対応しています.

Skeleton では

  • bindTransforms : いわゆるポーズ状態にする行列. World matrix になります.
  • restTransforms : usdSkel 固有っぽい概念? Maya での bindPose に対応するのでしょうか... こちらは local joint 行列(相対)になります. 基本は bindTransforms を相対にしたものが restTransforms になります.

SkelAnimation で joint に対してアニメーションの変換が指定されていたら, restTransforms ではなくて SkelAnimation の変換を使うようになります.

sparse = joint の一部だけにアニメーションが割あたっているの意味合いになります.

USD の仕様上だと non-sparse(つまり SkelAnimation での変換がすべての joint に指定されている)だと, restTranforms は省略可能とありますが, 実際のところ usdview などではうまく処理されなかったので,
bindTransformsrestTransforms は両方指定が必要になります(たぶん).

bindTransforms なくして restTransforms だけでいいような気もしますが, なんか両方(World と local)ないとだめなケースがあるのですかね...

Skin Weights

skin weight 自体はデータとしては必ずしも normalize はされておらず, また(USD の実装では)読み込み時でも自動で normalize は行われません.

Skinning 行列を求める

  • Skeleton での local で joint 点の変換
    • SkelAnimation で変換が joint に割あたっていればそれを使う
    • なければ restTransforms(local 行列)を使う
  • Skeleton での bindTranforms の逆行列
  • Mesh 側に primvars:skel:geomBindTransform があればそれを書ける
  • Mesh に xformOps がああればそれをかける(USD では Mesh 自体も xform を持てる)
  • SkelRoot に xformOps があればそれをかける
    • SkelRoot の子が Xform だったらその Xform をかける

でしょうか...
つまり,

P' = SkelRootXform x MeshXform x geomBindTransform x inv(Skeleton_bindTransforms) x Skeleton_restTransform_or_SkelAnimation

BlendShape

In-between shape 対応です.
Maya や Blender でのそれとほぼ同じで, USD だけの特殊な定義はないかと思われます.

In-between blendshape

Prim 変数に inbetweens namespace が付きます. また attribute metadatum で weight を指定します.

        def BlendShape "twirl_a"
        {
            uniform int[] pointIndices = [
                1, 2, 3, 4, 5, 6, 7, 8, 12, 13, 14, 15, 16, 17, 23, 24, 25, 26, 34, 35
            ]

            uniform point3f[] inbetweens:half = [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0)] (weight = 0.5)
        }

inbetweens:<name> で pointOffset 相当, inbetweens:<name>:normalOffsets で normalOffsets を指定します.

いくつかの sample USD では point3f を使っていますが, schema では vector3f のようです. とりあえず float3 型であればどれでもよいように解釈しないとダメそうです.

weight = 0weight = 1 は implicity に定義され, weight = 0 は offset がすべてゼロとして扱われれます.
weight = 1offsets attribute になります.

inbetween attribute で weight 0.0, 1.0 指定はエラーとなります.

また, inbeteeen attribute が同じ weight 値を持つ場合もエラーとすることが推奨されています
(重複を許すこともできはするるが, その場合どう扱うかが不明なため)

Binding

Maya でいうポーズバインドと思われるが...

T.B.W.

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?