スキニング

スキニングとは

スキニングとは、 ボーン(骨)などを使ってポリゴンを皮膚のように滑らかに変形させることを言います。 ToyStudioではメッシュ タイプ(TA_OBJECT_MESH)のオブジェクト(CTaObject)にボーンをセットし、 スキニングを行うことが出来ます。

スキニング用のデータ

ToyStudioでスキニングを利用するには、以下の5項目のデータが必要になります。 ToyStudioの「オブジェクト」メニューの「スムーズ スキニング」を実行すると1〜5のデータが作成され、 「スキニングをクリア」を実行すると削除されます。 「ボーン参照をクリア」を実行した場合、1〜4のデータは削除され5のデータは保持されます。

  1. ボーンのリスト
  2. スキンのバインド時ワールド変換行列
  3. ボーンのバインド時ワールド変換行列
  4. バインド ポーズ
  5. 頂点のボーン インデックスとウェイト

1.は全てのボーン オブジェクト(CTaObject)のリストで、 CTaObject::GetBones() で取得、 CTaObject::SetBones() でセットします。

2.は「スムーズ スキニング」実行時の、スキニングされるオブジェクトのワールド変換行列で、 CTaObject::GetSkinBindTransform() で取得、 CTaObject::SetSkinBindTransform() でセットします。

3.は「スムーズ スキニング」実行時の、全ボーンのワールド変換行列で、 CTaObject::GetBoneBindTransforms() で取得、 CTaObject::SetBoneBindTransforms() でセットします。

4.は「スムーズ スキニング」実行時の、 スキンと全ボーン、それらからルート モデルまでさかのぼる全ての親オブジェクトのユニーク リストと姿勢パラメータです。 これは、ToyStudioの「オブジェクト」メニューの「バインド ポーズ」コマンドで使用されます。 CTaObject::GetBindPose() で取得、 CTaObject::SetBindPose() でセットします。
つまり、これらの姿勢パラメータをそれぞれのオブジェクトにセットした状態で、 スキンおよび全ボーンについて CTaObject::GetWorldTransform() で取得されたものが、 それぞれ2.および3.の変換行列ということになります。

5.は各頂点が保持する4個(TA_MAX_VERTEX_BONE_COUNT)のボーン インデックスと、 ウェイトです。 ボーン インデックスは頂点が参照するボーンの1.のボーン リストにおける位置で、 ウェイトはその重みです。 CTaObject::GetVertexBones() で取得、 CTaObject::GetVertexBones() でセットします。

ボーン行列

スキンのバインド時ワールド変換行列を$S_b$、 ボーン$n$のバインド時ワールド変換行列を$B_{bn}$、 ボーン$n$の現在のワールド変換行列を$B_{cn}$、 スキンの現在のワールド変換行列を$S_c$とすると、 ToyStudioの表示に使用されているボーン$n$のボーン行列$M_n$

\[ M_n = (S_b\,B_{bn}^{-1})\,B_{cn}\,(S_b^{-1}\,S_c) \]

となります。$(S_b\,B_{bn}^{-1})$はXファイルにおける「ボーン オフセット行列」に相当します。 $(S_b^{-1}\,S_c)$は現在のスキン自体の姿勢パラメータを表示に反映させるための変換であり、 Xファイルなどでは使用されません。

スキニング処理

ToyStudioの表示では、以下のようなコード(簡易コード)を用いて頂点座標のスキニング処理を行っています。
//ボーン行列の配列
TA_MATRIX BoneMatrices[256];

//頂点のボーン インデックスの配列
BYTE Indices[TA_MAX_VERTEX_BONE_COUNT];

//頂点のボーン ウェイトの配列
float Weights[TA_MAX_VERTEX_BONE_COUNT];

//通常の頂点座標値
TA_VECTOR VertexPos;

//上記のデータは取得済みとします。

//求めるスキニング済み頂点座標値
TA_VECTOR Pos(0, 0, 0);

//計算用のウェイト値
float CurWeight = 0;

//TA_MAX_VERTEX_BONE_COUNT-1回のループ
for(UINT n = 0; n < TA_MAX_VERTEX_BONE_COUNT-1; ++n)
{
 //ウェイト値を取得
 float weight = Weights[n];

 //頂点座標値にボーン行列をかけ重みをつけて加算
 Pos += VertexPos*BoneMatrices[Indices[n]]*weight;

 //計算用のウェイト値を加算
 CurWeight += weight; 
}

//最後のウェイト値は1-CurWeight。
CurWeight = 1-CurWeight; 

//最後に頂点座標値にボーン行列をかけ重みをつけて加算
Pos += VertexPos*BoneMatrices[Indices[n]]*CurWeight;
この処理では、頂点の最後(TA_MAX_VERTEX_BONE_COUNT個め)のウェイト値は実際のスキニング処理には利用されず、 1からそれ以外のウエイトを引いたものが利用されます。 また、頂点のウェイト値が全て0の場合は最後のウェイト値が1として処理されます。


Generated for ToyStudio SDK 1.6.1.3 by  Doxygen