Trackball详解????

来源:互联网 发布:测试电池容量的软件 编辑:程序博客网 时间:2024/06/03 20:50

 

问题:后面的TrackballManipulator::tb_project_to_sphere()?????

 

void TrackballManipulator::computePosition(const osg::Vec3& eye,const osg::Vec3& center,const osg::Vec3& up)

{    osg::Vec3 lv(center-eye);

 

    osg::Vec3 f(lv);

    f.normalize();

    osg::Vec3 s(f^up);

    s.normalize();

    osg::Vec3 u(s^f);

    u.normalize();

   

    osg::Matrix rotation_matrix(s[0],     u[0],     -f[0],     0.0f,

                                s[1],     u[1],     -f[1],     0.0f,

                                s[2],     u[2],     -f[2],     0.0f,

                                0.0f,     0.0f,     0.0f,      1.0f);

   //矩阵rotation_matrix相当于把“倾斜”的uvn坐标系变为“正”的opengl标准坐标系,下面的_rotation是rotation_matrix的逆矩阵,相当于把“正”的opengl标准坐标系变为“倾斜”的uvn坐标系

    _center = center;

    _distance = lv.length();

    _rotation = rotation_matrix.getRotate().inverse();

}

---------

//将视点及其局部坐标系由opengl标准世界坐标系变换到最终“倾斜”的uvn坐标系。

osg::Matrixd TrackballManipulator::getMatrix()consts

{

    return osg::Matrixd::translate(0.0,0.0,_distance)*osg::Matrixd::rotate(_rotation)*osg::Matrixd::translate(_center);

}//改变视点坐标系,实质相当于改变视点坐标和旋转矩阵(R*T),它其实也相当于是把坐标系先平移(T)再旋转(R):

osg::Matrixd::rotate(_rotation )* osg::Matrixd::translate(_homeEye),但注意,这只是有时候成立,因为TrackballManipulator中鼠标操作是以改变_center为主的。

 

TrackballManipulator::getMatrix()相当于对视点及其局部坐标系进行变换:先平移到_center。将局部坐标系旋转成为“倾斜”的uvn坐标系将局部坐标系沿Z轴(即n轴)平移_distance的距离。如下图:

注意:对视点的变换是在opengl坐标系下,而不是在OSG坐标系下。

――――――――――

视图矩阵MV=TrackballManipulator::getInverseMatrix()。

――――――――――

void TrackballManipulator::setByMatrix(const osg::Matrixd& matrix)

{

    _center = osg::Vec3(0.0f,0.0f,-_distance)*matrix;

    _rotation = matrix.getRotate();

}

其中matrix是把视点及其局部坐标系变换为最终的视点及局部坐标系(uvn)。这样,(0.0f,0.0f,-_distance)表示在该uvn坐标系下z=-_distance的点,看上图的视点E及其uvn坐标系,可知该点是参考点_center。matrix.getRotate();就是将opengl标准世界坐标系变换到最终“倾斜”的uvn坐标系。

 

总之,可以看成是对局部坐标系的操作(进行一系列平移或旋转变换)。

 

――――――――――

用鼠标旋转轨迹球时:TrackballManipulator::calcMovement()中:

_rotation = _rotation*new_rotate;

它是在原来_rotation的基础上右乘的,为什么不左乘?原因如下(参考下图):在以_center为中心的opengl的XYZ坐标系(X朝右,Z朝屏幕外)下,视点v(0,0,_distance)在视点坐标系(XYZ)下的坐标v0=v*_rotation,而当用鼠标旋转轨迹球时,坐标v0应该绕opengl的XYZ坐标系下的某个轴n旋转一角度(设矩阵为R),此时新视点v1在opengl的XYZ坐标系下的坐标v1=v0*R,即v1=v*_rotation*R,即新的旋转矩阵为_rotation*R。

TrackballManipulator::calcMovement()

{……

else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||        buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON))//在与视线垂直的平面上平移相机

    {        // pan model.

        float scale = -0.3f*_distance;

        osg::Matrix rotation_matrix;

        rotation_matrix.makeRotate(_rotation);

        osg::Vec3 dv(dx*scale,dy*scale,0.0f);

        _center += dv*rotation_matrix;       

        return true;

}

/* dv*rotation_matrix相当于uvn坐标系中(dx*scale,dy*scale,0.0f)的向量,_center += dv*rotation_matrix即将参考点_center 在uvn坐标系的uv平面(或xy平面)上移动,相当于在与视线垂直的平面上平移相机*/

……

else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON)

{//缩放模型,即将参考点沿视线方向前进

float scale = -fd;

            osg::Matrix rotation_matrix(_rotation);

            osg::Vec3 dv = (osg::Vec3(0.0f,0.0f,-1.0f)*rotation_matrix)*(dy*scale);

 

        _center += dv;

/*(0.0f,0.0f,-1.0f)*rotation_matrix相当于uvn坐标系中的z=-1的向量(值是世界坐标值),_center += dv表示将参考点_center 向n轴负向平移1个单位,这样离物体更近*/

 

}

}