java - 四元数平滑旋转

标签 java 3d rotation quaternions jmonkeyengine

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

我希望模拟从一个方向到另一个方向的平滑旋转。我计算了开始方向 startOrientation 和结束方向 endOrientation 并希望将中间方向描述为 startOrientation*(1-argument) + endOrientation*argumentargument0 变为 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;
                }
            }
        }


    }

余弦公式有望模拟开始时的平滑加速和结束时的减速。

代码有效但不如预期:平滑旋转在 fractionargument 值达到 1 之前很久就开始和结束了,我没有不明白,为什么。

为什么 orientation 值达到 endOrientation 这么快?

最佳答案

您已经声明在您的案例中 startOrientation 正在被修改。然而;以下仍然成立

四元数之间的插值

为此目的,方法 slerp 包含在四元数类中:interpolating between two rotations.

假设我们有两个四元数 startOrientationendOrientation 并且我们想要它们之间的点 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 个四元数之间进行插值的偏航图

enter image description here

关于java - 四元数平滑旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24312200/

相关文章:

java - 如何在 Java 中旋转 BufferedImage?

java - 如何在java中获得一个开放的套接字?

ios - 核心动画 : moving a layer along a plane

html - 为什么div和旋转的div(三 Angular 形)之间有间隙

javascript - 使用 HTML/JS 或其他 Web 解决方案来渲染旋转的丝带

algorithm - 基于极值点的打包算法(3D)

javascript - 绕另一个旋转圆旋转一个圆

java - 如何在 IE 11 中使用 Selenium webdriver 单击安全警告窗口?

Java - OpenCV 忽略额外的轮廓

java - 用句点(.)分割的字符串表现出不同的行为