四元数不仅可以描述旋转,还可以描述方向,即从初始(零)位置开始的旋转。
我希望模拟从一个方向到另一个方向的平滑旋转。我计算了开始方向 startOrientation
和结束方向 endOrientation
并希望将中间方向描述为 startOrientation*(1-argument) + endOrientation*argument
而argument
从 0
变为 1
。
猴子引擎更新函数代码如下:
@Override
public void simpleUpdate(float tpf) {
if( endOrientation != null ) {
if( !started ) {
started = true;
}
else {
fraction += tpf * speed;
argument = (float) ((1 - Math.cos(fraction * Math.PI)) / 2);
orientation = startOrientation.mult(1-argument).add(endOrientation.mult(argument));
//orientation = startOrientation.mult(1-fraction).add(endOrientation.mult(fraction));
log.debug("tpf = {}, fraction = {}, argument = {}", tpf, fraction, argument);
//log.debug("orientation = {}", orientation);
rootNode.setLocalRotation(orientation);
if( fraction >= 1 ) {
rootNode.setLocalRotation(endOrientation);
log.debug("Stopped rotating");
startOrientation = endOrientation = null;
fraction = 0;
started = false;
}
}
}
}
余弦公式有望模拟开始时的平滑加速和结束时的减速。
代码有效但不如预期:平滑旋转在 fraction
和 argument
值达到 1
之前很久就开始和结束了,我没有不明白,为什么。
为什么 orientation
值达到 endOrientation
这么快?
最佳答案
您已经声明在您的案例中 startOrientation
正在被修改。然而;以下仍然成立
四元数之间的插值
为此目的,方法 slerp
包含在四元数类中:interpolating between two rotations.
假设我们有两个四元数 startOrientation
和 endOrientation
并且我们想要它们之间的点 interpolation
然后我们使用以下代码进行插值:
float interpolation=0.2f;
Quaternion result=new Quaternion();
result.slerp(startOrientation, endOrientation, interpolation);
为什么你的方法可能是危险的
四元数在内部有些复杂,并且遵循一些不同的数学规则来表示 vector 。您已对四元数调用了 multiply(float scalar)
方法。在内部这看起来像这样
public QuaternionD mult(float scalar) {
return new QuaternionD(scalar * x, scalar * y, scalar * z, scalar * w);
}
所以它只是对所有元素进行简单的乘法运算。这明确不会返回 标量
乘以大小的旋转。事实上,这样的四元数不再代表有效的旋转,因为它不再是单位四元数。如果您对该四元数调用 normalise
,它会立即撤消缩放。我确定 Quaternion#multiply(float scalar)
有一些用处,但我还没有找到它们。
“相加”四元数并没有组合起来也是这样。事实上,你乘以它们。所以结合 q1 然后 q2 然后 q3 将实现如下:
Quaternion q0 = q1.mult(q2).mult(q3);
cheat sheet对此非常有用
公式与 slerp 比较
在您的情况下,您的插值公式几乎但不完全正确。这显示了使用两种方法在 2 个四元数之间进行插值的偏航图
关于java - 四元数平滑旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24312200/