背景
USDZ で AR データのアニメーション(excludes timeSamples)を極めたい.
UsdSkel
機能としては
- (vertex) skinning
- blendshape
- binding
の 3 つっぽい.
skinning と blendshape については, 大まかには glTF や Maya でのそれ(skinning, blendshape)と同じと考えられる.
binding は Maya でいうポーズバインドでしょうかね.
(glTF には対応するものは (explicitly には) ない気がする)
Schema
および USD のソースコードに schema 定義があります.
ただ, schema 自体はあまり参考にならないかもです.
参考情報
記述
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 などではうまく処理されなかったので,
bindTransforms
と restTransforms
は両方指定が必要になります(たぶん).
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 = 0
と weight = 1
は implicity に定義され, weight = 0
は offset がすべてゼロとして扱われれます.
weight = 1
は offsets
attribute になります.
inbetween attribute で weight 0.0, 1.0 指定はエラーとなります.
また, inbeteeen attribute が同じ weight 値を持つ場合もエラーとすることが推奨されています
(重複を許すこともできはするるが, その場合どう扱うかが不明なため)
Binding
Maya でいうポーズバインドと思われるが...
T.B.W.