四元数平滑旋转

Dim*_*ims 5 java 3d rotation quaternions jmonkeyengine

四元数不仅可以描述旋转,还可以描述方向,即从初始(零)位置旋转.

我希望模拟从一个方向到另一个方向的平滑旋转.余计算开始定向startOrientation和结束定向endOrientation,并希望描述中间取向为startOrientation*(1-argument) + endOrientation*argument同时argument从变化01.

猴子引擎更新功能的代码如下:

@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;
                }
            }
        }


    }
Run Code Online (Sandbox Code Playgroud)

预计余弦公式可以在开始时模拟平滑加速,在结束时减速.

代码可以工作但不是预期的:平滑的旋转开始并很久以前完成fraction并且argument值达到1,我不明白,为什么.

为什么orientation价值endOrientation如此之快?

Ric*_*gle 4

您已经说过,您的情况startOrientation正在被修改。然而; 以下内容仍然正确

四元数之间的插值

该方法slerp包含在 Quaternion 类中,用于实现以下目的:在两个旋转之间进行插值。

假设我们有两个四元数startOrientation,并且endOrientation我们想要它们之间的点interpolation,那么我们使用以下代码在它们之间进行插值:

float interpolation=0.2f;
Quaternion result=new Quaternion();
result.slerp(startOrientation, endOrientation, interpolation);
Run Code Online (Sandbox Code Playgroud)

为什么你的方法可能很危险

四元数内部有些复杂,并且遵循与向量不同的数学规则。您已调用multiply(float scalar)四元数上的方法。内部看起来像这样

public QuaternionD mult(float scalar) {
        return new QuaternionD(scalar * x, scalar * y, scalar * z, scalar * w);
}
Run Code Online (Sandbox Code Playgroud)

所以它只是对所有元素进行简单的乘法。这明确不会返回乘以大小的旋转。scalar事实上,这样的四元数根本不再代表有效的旋转,因为它不再是单位四元数。如果您调用normalise这个四元数,它将立即撤消缩放。我确信 Quaternion#multiply(float scalar)有一些用处,但我还没有找到它们。

“添加”四元数也不会合并它们。事实上,你将它们相乘。因此,组合 q1、q2、q3 将得到如下结果:

Quaternion q0 = q1.mult(q2).mult(q3);
Run Code Online (Sandbox Code Playgroud)

备忘对此非常有用

公式与 slerp 比较

在您的情况下,您的插值公式几乎但不完全正确。这显示了使用两种方法在 2 个四元数之间插值的偏航图

在此输入图像描述