glm :: mix返回无效的四元数

时间:2012-07-20 02:18:01

标签: c++ opengl quaternions

我正在尝试将骨骼动画应用到我的游戏引擎中,我对插值有问题。

每一帧,我想在帧之间插值,因此我有类似的代码:

// 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)

这些是一些示例值及其结果(请注意,interpolation在所有三种情况下均为0.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) (不正确)

(是的,我知道它在相同的值之间进行插值。)

我还没有准确掌握四元数是如何工作的,但这对我来说似乎很奇怪。

1 个答案:

答案 0 :(得分:2)

如果查看typical Slerp equation,您会看到它在分数的分母中有一个Sin(Ω),其中Ω是两个四元数之间的角度:即Ω = 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已经注释掉了,可以更好地处理这些问题。在2011年5月,当前版本及其附带的问题似乎是committed to the repository

如果角度小于某个阈值量,我建议恢复使用线性插值的版本。只需注释掉当前内容并取消旧内容即可。