5

约束 3D 旋转的正确/最佳方法是什么(使用欧拉角和/或四元数)?

看来我的做法有问题。我将旋转应用于骨骼层次结构中的骨骼以进行动画处理,并且骨骼有时会明显地“跳”到错误的方向,并且各个 Euler 组件会环绕到其范围的另一端。

我使用欧拉角来表示当前方向,转换为四元数进行旋转,并独立夹紧每个欧拉角轴。这是 C++ 伪代码,基本上显示了我在做什么:

Euler min = ...;
Euler max = ...;

Quat rotation = ...;
Euler eCurrent = ...;

// do rotation
Quat qCurrent = eCurrent.toQuat();
qCurrent = qCurrent * rotation;
eCurrent = qCurrent.toEuler();

// constrain
for (unsigned int i = 0; i < 3; i++)
    eCurrent[i] = clamp(eCurrent[i], min[i], max[i]);
4

2 回答 2

1

欧拉角的一个问题是有多种方法可以表示相同的旋转,因此您可以轻松创建一系列平滑的旋转,但表示该旋转的角度可能会跳来跳去。如果角度跳入和跳出约束范围,那么您将看到您所描述的效果。

想象一下,仅涉及 X 旋转,并且您已将 X 旋转限制在 0 到 180 度之间。还想象一下,将四元数转换为欧拉角的函数给出了 -180 到 180 度的角度。

然后你有这个旋转序列:

True rotation    After conversion    After constraint
179              179                 179
180              180                 180
181             -179                 0

可以看到,即使旋转是平滑变化的,结果也会突然从一侧跳到另一侧,因为转换函数强制结果在一定范围内表示。

将四元数转换为欧拉角时,请找到最接近先前结果的角度。例如:

eCurrent = closestAngles(qCurrent.toEuler(),eCurrent);
eConstrained = clampAngles(eCurrent,min,max);

记住下次的 eCurrent 值,并将 eConstrained 旋转应用于您的骨架。

于 2012-05-20T13:49:52.887 回答
0

这里的问题是您应用的约束与应用的旋转无关。从概念的角度来看,这就是您要实现的目标:

  • 假设骨骼处于无约束状态。
  • 应用旋转
  • 骨骼是否超出限制?如果是,将其旋转到不再受约束的位置

钳制欧拉旋转的代码是您将骨骼向后旋转的部分。但是,此代码忽略了原始骨骼旋转,因此您会看到奇怪的行为,例如您看到的捕捉。

一个简单的方法是这样做:

  • 假设骨骼处于无约束状态
  • 应用旋转
  • 测试骨骼是否超出约束
  • 如果是,我们需要找到约束停止移动的位置。
    1. 将旋转减半,反向应用
    2. 骨骼是否超出约束?如果是,请转到 1
    3. 如果不是,则将旋转减半,然后将其应用到正向。转到 2
  • 继续这样做,直到您在约束​​角度的某个公差范围内

现在这将起作用,但是因为您的旋转四分位数被应用于所有角度,所以当这些约束中的任何一个为净时,旋转将停止,即使在其他地方有自由也是如此。

相反,如果您彼此独立地应用旋转,那么您将能够可靠地使用您的夹紧或上述技术来遵守约束,并尽可能靠近您的目标旋转。- -

于 2012-05-20T05:31:33.200 回答