How to derive “standard” rotations from three.js when using quaternions?

后端 未结 2 1923
刺人心
刺人心 2020-12-31 19:00

Newbie stackoverflow participant, newbie 3D programmer, and far from a math wiz... so I\'ll try to frame this question as clearly as I can, hoping it makes sense, and hoping

相关标签:
2条回答
  • 2020-12-31 19:46

    This is a good question.

    When an object is in it's default orientation, it can be considered to be looking in the direction of it's internal, positive z-axis. (The exception is the camera, which is looking in the direction of its internal negative z-axis.)

    Therefore, when an object is rotated, you can get the direction the object is facing by applying the object's quaternion to a unit vector pointing in the direction of the positive z-axis (negative z-axis for the camera).

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

    This will return a unit vector pointing in the direction the object is "facing".

    If the object is a child of another rotated object, then the situation is more complicated.

    EDIT: updated for r.58. Thanks @eshan.

    0 讨论(0)
  • 2020-12-31 19:53

    Thanks for the quick response - it wasn't exactly what I was looking for, but I probably didn't know how to ask the question clearly. My specific use-case was that I wanted to draw a 2D map the represented the relative positions of all the objects in my 3D scene, but I wanted to rotate the objects in the map based on the yaw of the camera in the 3D scene - so I needed to know the "angle" that the quaternion-based camera was facing so that I could offset the rotations of the 2D objects on the map accordingly. Seems to work pretty well. I just wish there didn't have to be so many calculations, but at least Javascript is fast.

    // 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
    }
    
    0 讨论(0)
提交回复
热议问题