使用四元数围绕两个世界轴旋转对象

时间:2014-03-13 16:26:00

标签: rotation three.js quaternions

我试图通过用鼠标拖动来旋转three.js中的对象,因此它必须围绕x和y轴旋转。如果我只尝试围绕一个轴旋转,我编写的代码工作得很好,但是当我尝试围绕两个轴旋转时,旋转变得奇怪,即使鼠标只朝一个方向移动,它也总是围绕两个轴旋转:

function onDocumentMouseDown( event ) {
            document.addEventListener( 'mousemove', onDocumentMouseMove, false );

            //mouse point normalized to world coords
            lastPoint = {
                x : (event.clientX / windowHalfX)  * 2 - 1,
                y : -(event.clientY / windowHalfY)  * 2 + 1
            };

        }

        function onDocumentMouseMove( event ) {
            //new mouse position normalized to world coords
            newPoint = {
                x : (event.clientX / windowHalfX)  * 2 - 1,
                y : -(event.clientY / windowHalfY)  * 2 + 1
            };

            //rotation for both x and y axis
            rotationY = Math.atan(1 / (newPoint.x - lastPoint.x )) * (Math.PI / 180);
            rotationX = Math.atan(1 / (lastPoint.y - newPoint.y )) * (Math.PI / 180);   

            //apply rotation on Y axis
            quaternion.setFromAxisAngle( new THREE.Vector3(0,1,0).normalize(), rotationY); 
            cube.quaternion.multiplyQuaternions( quaternion, cube.quaternion ); 

            //aply rotation on X axis
            quaternion.setFromAxisAngle( new THREE.Vector3(1,0,0).normalize(), rotationX); 
            cube.quaternion.multiplyQuaternions( quaternion, cube.quaternion );

            //update last position to current one
            lastPoint = {
                x : newPoint.x,
                y : newPoint.y
            };
        }

我总是围绕两个轴应用旋转,但是当鼠标沿一个方向移动时,围绕另一个轴的旋转应该是0或接近0,但旋转非常大且明显。

任何人都可以指出我做错了吗?

由于

1 个答案:

答案 0 :(得分:1)

你的关键词是"弧球"控制。下面的伪代码说明了它

/**
 help function for arcball 
 orthogonal projection on sphere of radius 1, 
 standing in (x = 0, y = 0)
*/
inline vector3 ortho_project_on_sphere( float x , float y )
{
    vector3 p(x, y, 0);
    float ls = p.len_squared();
    if ( ls >= 1.0f )
        p.norm();
    else
        p.z = (float)sqrt(1.0f - ls);
    return p;
}
//-------------------------------------------------------------------------------
/*
  calculate rotation of arcball user input,
  used to perform object rotation by mouse.
  "from" and "to" the mouse on screen coordinates (with - x,y on screen) 
  in range of -1 to +1 
  the arcball radius is 1.0 and it stand in a center (x = 0, y = 0)
*/
inline xxquaternion arcball(const vector3& from, const vector3& to)
{
    vector3 p_f = ortho_project_on_sphere(from.x, from.y );
    vector3 p_t = ortho_project_on_sphere(to.x, to.y );
    vector3 c   = cross(p_f, p_t);
    float   d   = dot(p_f, p_t);
    return  xxquaternion(c.x, c.y, c.z, d);
}