如何约束3D旋转(欧拉)

时间:2012-05-19 05:01:14

标签: c++ animation 3d

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

我的做法似乎有些不对劲。我正在将旋转应用于动画骨架层次结构中的骨骼,并且骨骼有时会明显“跳”到错误的方向,并且各个欧拉组件会绕到它们范围的另一端。

我使用欧拉角来表示当前方向,转换为四元数以进行旋转,并且独立地夹住每个欧拉角轴。这是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]);

2 个答案:

答案 0 :(得分:0)

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

  • 假设骨骼处于不受约束的状态。
  • 申请轮换
  • 骨超出约束?如果是,请将其旋转到不再受限制的地方

夹住Euler旋转的代码是将骨骼旋转回来的部分。但是,此代码忽略原始骨骼旋转,因此您将看到奇怪的行为,例如您看到的捕捉。

使用它的一个简单方法是改为:

  • 假设骨骼处于不受约束的状态
  • 申请轮换
  • 测试骨骼是否超出约束
  • 如果是,我们需要找到约束停止移动的位置。
    1. 将旋转减半,反向应用
    2. 骨头是否超出限制?如果是,请转到1
    3. 如果不是,将旋转减半,则向前施加。转到2
  • 继续这样做,直到你在约束角度的某个容忍范围内

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

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

答案 1 :(得分:0)

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

想象一下,只涉及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旋转应用于骨架。