スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

避けて通れないモーション補間 その2

モーションを適用するには、まず適用前のキーフレームと適用後を取得します。
そのキーフレームの変換行列をインポータで登録しておくわけですが、
サンプルには大抵二種類パターンがあります。

行列のみで所持している場合



行列をSRTに分解した値でもっている場合

です。

計算自体はSRTのほうが軽いのかな。
もしScaleを使わないスキンモデルを扱うなら、vec3の位置情報とクォータニオンの回転情報を持った構造体を作成して所持させることで行列変換と比べて使用メモリを半分以下に抑えられるそうです。
ちなみにSRTとはscale、rtation、translationです。
amountとは補間係数となります。(詳しくはwebで)

さて、
scales[Index] = Vector3.Lerp(beforeKeyframe.scale, afterkeyframe.scale, amount);
rotations[Index] = Quaternion.Slerp(beforeKeyframe.rotation, afterkeyframe.rotation, amount);
translations[Index] = Vector3.Lerp(beforeKeyframe.translation, afterkeyframe.translation, amount);


こんな感じで補間していたのですがどうも怪しいモーションがポツポツと・・・

ちなみにSRTを行列にしたい場合は
行列 = Matrix.CreateScale(scales[Index])
* Matrix.CreateFromQuaternion(rotations[Index])
* Matrix.CreateTranslation(translations[Index]);

となります。

モーションをブレンドをしたい場合は行列であろうとSRTであろうとこう考えます。

これだと崩れる
モーションAの要素 に モーションBの要素 を加える


こっちならOK
モーションAの要素の5割 に モーションBの要素の5割 を加える


この5割に当たる部分(%)をウェイトとして考え、比重を変えてやることで遷移をスムーズにします。

SRTの場合をソースで見てみると
if (Weight != 1.0f)
{
scales[Index] = (scales[Index] - Vector3.One) * Weight + Vector3.One;
rotations[Index] = Quaternion.Lerp(Quaternion.Identity, rotations[Index], Weight);
translations[Index] *= Weight;
}

こんな感じ。

っとまぁここまでやってきたのはいいのですが・・・回転の補間がなんかあやしい?
SRTを得る時に使っているMatrix.Decomposeメソッドがおかしいのか、Leapがおかしいのか・・・
数学的なものなので
「知識さえあればその場で検証できる!」
のですが、例のごとく
「そんなものは無い!」

困った。
歪みが出るモーションをACLで表示させてみたところ、ありゃ綺麗。それならそのまま補間のソースを移植してしまえってわけで
public sealed class func
{
private static Quaternion qStart, qEnd, qResult;
private static Vector3 curTrans, nextTrans, lerpedTrans;
private static Vector3 curScale, nextScale, lerpedScale;
private static Matrix startRotation, endRotation;
private static Matrix returnMatrix;
public static Matrix SlerpMatrix(Matrix start, Matrix end,float slerpAmount)
{
if (start == end)
return start;
//回転行列はQuaternion.SlerpではなくQuaternion.Lerp
Quaternion.CreateFromRotationMatrix(ref start, out qStart);
Quaternion.CreateFromRotationMatrix(ref end, out qEnd);
Quaternion.Lerp(ref qStart, ref qEnd, slerpAmount, out qResult);

//平行移動行列はVector3.Lerpを使っている
curTrans.X = start.M41;
curTrans.Y = start.M42;
curTrans.Z = start.M43;
nextTrans.X = end.M41;
nextTrans.Y = end.M42;
nextTrans.Z = end.M43;
Vector3.Lerp(ref curTrans, ref nextTrans, slerpAmount, out lerpedTrans);

//拡大縮小行列にはVector3.Lerp
Matrix.CreateFromQuaternion(ref qStart, out startRotation);
Matrix.CreateFromQuaternion(ref qEnd, out endRotation);
curScale.X = start.M11 - startRotation.M11;
curScale.Y = start.M22 - startRotation.M22;
curScale.Z = start.M33 - startRotation.M33;
nextScale.X = end.M11 - endRotation.M11;
nextScale.Y = end.M22 - endRotation.M22;
nextScale.Z = end.M33 - endRotation.M33;
Vector3.Lerp(ref curScale, ref nextScale, slerpAmount, out lerpedScale);

//srt行列を作成してMatrix.CreateScale(S*R*T)と同じことをしている(こっちのが断然軽い)
Matrix.CreateFromQuaternion(ref qResult, out returnMatrix);
returnMatrix.M41 = lerpedTrans.X;
returnMatrix.M42 = lerpedTrans.Y;
returnMatrix.M43 = lerpedTrans.Z;
returnMatrix.M11 += lerpedScale.X;
returnMatrix.M22 += lerpedScale.Y;
returnMatrix.M33 += lerpedScale.Z;
return returnMatrix;
}
}


さっそく
求めたい変換行列 = func.SlerpMatrix(beforeKeyframe, afterkeyframe, amount);
で補間をしてみたところ綺麗に描写することができた!外国人はやっぱりすばらしい。

Animation Component Libraryのライセンスは
http://www.codeplex.com/animationcomponents/license
WEB和訳:
これにより許可を与えます。
無料です。ファイル(「ソフトウェア」)が使用する権利(コピー)が変更する制限なしで包含することでのマージが発行されるという制限のないSoftwareでの取引に配布するこのソフトウェアと関連ドキュメンテーションのコピーを入手するどんな人にも、二次認可、Softwareの本を販売して、Softwareがそう以下の条件を条件としてするために提供される許可証人々に二次認可になってください:

「そのままで」ソフトウェアを提供します、どんな急行の、または、暗示している種類の保証も他を含むことのない市場性の保証、特定の目的AND NONINFRINGEMENTのためのフィットネス。
そうでなければ、契約の筋か不法行為か起こることにかかわらず作者か著作権保有者がソフトウェアにおける取り引きソフトウェア、使用または他の取り引きに関してどんなクレーム、損害賠償の、または、他の責任にも決して、責任がないでしょう。



こうやって調べてみるとXNAのモーションを解説したサイトはかなり少ないです。
数学的な文章がどうしても増えてしまうために敬遠されるのだろうか・・・
といってもプログラムやってて数学嫌いな人はいないだろうに・・・・



あ、ここにいた。



算数は好きなんだけどね。



ねよっと。

コメントの投稿

非公開コメント

プロフィール

あしゅ

Author:あしゅ
ぷぃぷぃ日常。
いつのまにか雑記ブログに。

カテゴリ
最新記事
検索フォーム
最新コメント
リンク
このブログをリンクに追加する
ブロとも申請フォーム

この人とブロともになる

カウンター
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。