8

新手 stackoverflow 参与者,新手 3D 程序员,远非数学奇才......所以我会尽可能清楚地提出这个问题,希望它是有道理的,并希望得到一个不超过我头脑的答案。

我使用 three.js 编写了一个非常酷的应用程序,它可以让用户飞过 3D 空间并探索太阳系。飞行模型松散地基于 three.js 包中的 Fly.Controller 示例/扩展,它教会我使用四元数来保持所有轴旋转相对于彼此合理。飞行部分都很好用。

这是我的困境:当使用四元数时,我如何推导出“正常”(我不知道还能怎么称呼它)旋转值来确定我面对的方向?使用四元数时,相机对象内部的“旋转”结构保持在 0,0,0。所以,虽然我可以在任何角度自由地在太空中飞行,但我不知道如何确定我实际面对的方向。是否有内置的 three.js 函数,或其他简单的方法来转换它?

我在网上找到了一些类似的、令人困惑的指针,但我无法破译并在 three.js 中使用。谢谢。

4

2 回答 2

6

这是一个很好的问题。

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

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

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

这将返回一个指向对象“面向”的方向的单位向量。

如果对象是另一个旋转对象的子对象,那么情况就更复杂了。

编辑:为 r.58 更新。谢谢@eshan。

于 2013-01-05T04:18:33.167 回答
0

感谢您的快速回复 - 这不是我想要的,但我可能不知道如何清楚地提出这个问题。我的具体用例是我想绘制一个 2D 地图,表示我的 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
}
于 2013-01-10T23:45:15.593 回答