1

ゲームエンジンにスケルタルアニメーションを実装しようとしていますが、補間に問題があります。

各フレーム、フレーム間を補間したいので、次のようなコードがあります。

// This is the soon-to-be-interpolated joint
Joint &finalJoint = finalSkeleton.joints[i];

// These are our existing joints
const Joint &joint0 = skeleton0.joints[i];
const Joint &joint1 = skeleton1.joints[i];

// Interpolate
finalJoint.position = glm::lerp(joint0.position, joint1.position, interpolate);
finalJoint.orientation = glm::mix(joint0.orientation, joint1.orientation, interpolate);

最後の行が問題です。の向きfinalJointは時々です(-1.#IND, -1.#IND, -1.#IND, -1.#IND)

これらはいくつかの値の例とその結果です(3つのケースすべてにあることに注意してください)interpolation0.4

  • joint0.orientation = (0.707107, 0.000242, 0.707107, 0.0)
    joint1.orientation = (0.707107, 0.000242, 0.707107, 0.0)
    finalJoint = (-1.#IND, -1.#IND, -1.#IND, -1.#IND) (正しくない)

  • joint0.orientation = (-0.451596, -0.61858, -0.262811, -0.586814)
    joint1.orientation = (-0.451596, -0.61858, -0.262811, -0.586814)
    finalJoint = (-0.451596, -0.61858, -0.262811, -0.586814) (正しい)

  • joint0.orientation = (0.449636, 0.6195, 0.26294, 0.58729)
    joint1.orientation = (0.449636, 0.6195, 0.26294, 0.58729)
    finalJoint = (-1.#IND, -1.#IND, -1.#IND, -1.#IND) (正しくない)

(はい、同じ値の間を補間していることを認識しています。)

クォータニオンがどのように機能するかはまだ正確には把握していませんが、これは私には奇妙に思えます。

4

1 に答える 1

2

典型的な Slerp 方程式 を見ると、分数の分母にa が含まれていることがわかります。Sin(Ω)ここで、Ω は 2 つの四元数の間の角度です。ウィキペディアの記事で述べたように、これは除去可能な不連続性ですが、少し追加のチェックが必要です。Ω = acos(dot_product(q1,q1));Sin(0)==0;

コードを引っ張って見てみました。その合計は次のとおりです。

T angle = acos(dot(x, y));
return (glm::sin((T(1)-a)*angle)*x+glm::sin(a*angle)*y)/glm::sin(angle);

特別なチェックはありません。これは、角度がゼロに近づくにつれて、数値的な問題が発生する傾向があります。また、一部の補間では、回転球の周りに長い道のりがかかる場合があります。glm:::mix の他の 2 つのバージョンがコメントアウトされており、これらの問題をより適切に処理しています。現在のバージョンとそれに伴う問題は、2011 年 5 月にリポジトリにコミットされたようです

角度がしきい値よりも小さい場合は、線形補間を使用するバージョンに戻すことをお勧めします。現在のものをコメントアウトし、古いものをコメント解除するだけです。

于 2012-07-24T16:54:58.667 に答える