【问题标题】:Smooth rotation with quaternions使用四元数平滑旋转
【发布时间】:2014-06-19 16:55:26
【问题描述】:

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

我希望模拟从一个方向到另一个方向的平滑旋转。我计算了起始方向startOrientation 和结束方向endOrientation,并希望将中间方向描述为startOrientation*(1-argument) + endOrientation*argument,而argument0 更改为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 这么快?

【问题讨论】:

    标签: java 3d rotation quaternions jmonkeyengine


    【解决方案1】:

    您已声明在您的情况下startOrientation 正在被修改。然而;以下仍然正确

    四元数之间的插值

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

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

    float interpolation=0.2f;
    Quaternion result=new Quaternion();
    result.slerp(startOrientation, endOrientation, interpolation);
    

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

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

    public QuaternionD mult(float scalar) {
            return new QuaternionD(scalar * x, scalar * y, scalar * z, scalar * w);
    }
    

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

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

    Quaternion q0 = q1.mult(q2).mult(q3);
    

    cheat sheet 对此非常有用

    公式与 slerp 比较

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

    【讨论】:

    • 显然slerp 的行为方式与我的函数相同:在interpolation 到达1 之前,旋转视觉上到达最终方向。
    • 我也没有看到 slerp 与您的原型:hub.jmonkeyengine.org/javadoc/com/jme3/math/…, float)">它无效,或 需要 3 个四元数.
    • @Dims 您在 slerp 方法签名上是正确的。似乎 JMonkey 文档中的一些已过时,已编辑。
    • @Dims 关于旋转太快。当它达到 1 时会发生什么。它旋转得太远了吗?还是在(例如)插值=0.8f 处突然停止
    • 终于发现了一个bug。我的startOrientation 是一个在此过程中发生变化的参考。在我克隆它之后,程序开始同时使用slerp 和我的公式。也许slerp 只是做了类似的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    相关资源
    最近更新 更多