使用四元数时,如何从three.js中推导出“标准”旋转?

8
新手stackoverflow参与者,新手3D程序员,远非数学高手……所以我会尽可能清晰地提出这个问题,希望它有意义,并希望得到一个不难理解的答案。
我使用three.js编写了一个非常酷的应用程序,让用户飞越三维空间,探索太阳系。飞行模型基于three.js包中的Fly.Controller示例/扩展,教我如何使用四元数来使所有轴旋转相对合理。飞行部分全部正常工作。
这就是我的困境:在使用四元数时,我该如何推断“正常”(我不知道该叫什么)旋转值以确定我面向哪个方向?当使用四元数时,摄像机对象内部的“旋转”结构保持为0,0,0。因此,虽然我可以自由地以任何角度飞行穿越空间,但我无法确定我实际上面向哪个方向。是否有内置的three.js函数或其他简单的方法可以转换此内容?
我在网上找到了一些类似的混乱指针,但没有什么能够在three.js中解释和使用的东西。谢谢。
2个回答

7

这是一个很好的问题。

当一个对象处于默认方向时,可以认为它朝着其内部的正z轴方向。 (例外是相机,它朝着其内部的 z轴方向。)

因此,当一个对象被旋转时,您可以通过将该对象的四元数应用于指向正z轴(对于相机为负z轴)方向的单位向量来获得对象面对的方向。

var zVec = new THREE.Vector3( 0, 0, 1 );
zVec.applyQuaternion( object.quaternion );

这将返回一个单位向量,指向物体所“面对”的方向。

如果物体是另一个旋转物体的子对象,则情况会更加复杂。

编辑:已更新至r.58版本。感谢@eshan。


非常感谢,这将是一条有用的信息,但这并不完全是我所期望的。我的目标是进行一种转换,使您可以将一个对象当前的“四元数”字段设置应用于另一个对象的“旋转”字段(即:一个不使用四元数的对象)。我想我找到了我正在寻找的解决方案,并将尝试将其发布为其他答案。谢谢! - J Sprague
似乎multiplyVector3方法现在已经被弃用了,但是您可以通过执行zVec.applyQuaternion(object.quaternion)来实现相同的效果。 - eshan
@WestLangley,能否请您看一下我的相关问题:https://stackoverflow.com/questions/71384648/threejs-rotate-subcomponent-of-object3d - Rylan Schaeffer

0
谢谢您的快速回复 - 那不完全是我要找的,但我可能不知道如何清楚地提问。我的具体用例是,我想绘制一个二维地图,该地图表示3D场景中所有对象的相对位置,但我想根据3D场景中相机的偏航角旋转地图上的对象-因此,我需要知道基于四元数的相机面对的“角度”,以便我可以相应地偏移地图上2D对象的旋转。看起来效果很不错。我只希望不必进行那么多的计算,但至少Javascript很快。
// Pass the obj.quaternion that you want to convert here:
//*********************************************************
function quatToEuler (q1) {
    var pitchYawRoll = new THREE.Vector3();
     sqw = q1.w*q1.w;
     sqx = q1.x*q1.x;
     sqy = q1.y*q1.y;
     sqz = q1.z*q1.z;
     unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
     test = q1.x*q1.y + q1.z*q1.w;
    if (test > 0.499*unit) { // singularity at north pole
        heading = 2 * Math.atan2(q1.x,q1.w);
        attitude = Math.PI/2;
        bank = 0;
        return;
    }
    if (test < -0.499*unit) { // singularity at south pole
        heading = -2 * Math.atan2(q1.x,q1.w);
        attitude = -Math.PI/2;
        bank = 0;
        return;
    }
    else {
        heading = Math.atan2(2*q1.y*q1.w-2*q1.x*q1.z , sqx - sqy - sqz + sqw);
        attitude = Math.asin(2*test/unit);
        bank = Math.atan2(2*q1.x*q1.w-2*q1.y*q1.z , -sqx + sqy - sqz + sqw)
    }
    pitchYawRoll.z = Math.floor(attitude * 1000) / 1000;
    pitchYawRoll.y = Math.floor(heading * 1000) / 1000;
    pitchYawRoll.x = Math.floor(bank * 1000) / 1000;

    return pitchYawRoll;
}        

// Then, if I want the specific yaw (rotation around y), I pass the results of
// pitchYawRoll.y into the following to get back the angle in radians which is
// what can be set to the object's rotation.

//*********************************************************
function eulerToAngle(rot) {
    var ca = 0;
    if (rot > 0)
        { ca = (Math.PI*2) - rot; } 
    else 
        { ca = -rot }

    return (ca / ((Math.PI*2)/360));  // camera angle radians converted to degrees
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接