OSG世界坐标转屏幕坐标(转载)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OSG世界坐标转屏幕坐标(转载)相关的知识,希望对你有一定的参考价值。

OSG世界坐标转屏幕坐标

#define M(row,col) m[col * 4 + row]

void Transform_Point(double out[4], const double m[16], const double in[4]){
    out[0] = M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
    out[1] = M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
    out[2] = M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
    out[3] = M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
}


osg::Vec3d WorldToScreen(osgViewer::View* view,osg::Vec3 worldpoint){
    double in[4], out[4];

    in[0] = worldpoint._v[0];
    in[1] = worldpoint._v[1];
    in[2] = worldpoint._v[2];
    in[3] = 1.0;
    //获得当前的投影矩阵和模型视图矩阵

    osg::Matrix projectMatrix= view->getCamera()->getProjectionMatrix();
    osg::Matrix viewprojectMatrix = view->getCamera()->getViewMatrix();
    //下面计算 模型视图矩阵 * 投影矩阵 * 视口窗口变换矩阵
    double modelViewMatrix[16];
    memcpy(modelViewMatrix,viewprojectMatrix.ptr(),sizeof(GLdouble) * 16);
    Transform_Point(out, modelViewMatrix, in);

    double myprojectMatrix[16];
    memcpy(myprojectMatrix,projectMatrix.ptr(),sizeof(GLdouble) * 16);

    Transform_Point(in, myprojectMatrix, out);

    if(int(in[3] * 100000) == 0){
       return osg::Vec3d(0,0,0);
    }

    in[0] /= in[3];
    in[1] /= in[3];
    in[2] /= in[3];

    int viewPort[4];
    osg::Viewport* myviewPort = view->getCamera()->getViewport();
    viewPort[0] = 0;
    viewPort[1] = 0;
    viewPort[2] = mConfigure->GetScreenWidthPixel(); //横向象素点
     viewPort[3] = mConfigure->GetScreenHeightPixel();//纵向象素点
    //计算 三维点在屏幕上的二维投影点
    osg::Vec3d sceenPoint;
    sceenPoint._v[0] = (int)(viewPort[0] + (1 + in[0]) * viewPort[2] / 2 + 0.5);
    sceenPoint._v[1] = (int)(viewPort[1] + (1 + in[1]) * viewPort[3] / 2 + 0.5);
    sceenPoint._v[2] = 0;
    return sceenPoint;
}

 
 
一颗场景树,远不止只有叶子节点Geode 因此.在osg中有着一些各种各样的组节点.osg::Group.还有许多从osg::Group 继承的其他各种各样的组节点.类太多了.附类继承图地址

       我目前只是尝试使用了MatrixTransform PositionAttitudeTransform Group Projection Switch 等各种功能的组节点.  在介绍MatrixTransform 和 PositionAttitudeTransform 节点前.我想先介绍下osg当中矩阵的一些相关知识. 

       其实,无需关心osg矩阵是如何实现的.但是要记住的是osg中采用的左乘操作,我们平时里讨论的操作如旋转平移等.
      OpenGL的:    newpos = R* T * oldpos    //先执行平移 后执行 旋转 (全局坐标系)
      osg当中:  newpos  =oldpos * T *R    //先执行平移 后执行旋转    (全局坐标系)
因为在osg当中矩阵执行的操作则是行矩阵操作.因此为了跟OpenGL的列矩阵做同步 而不在定义的时候就相当于做了一个转置操作.即
 技术分享

因此在osg/State 中 在使用applyModelViewMatrix()   osg/State 是OpenGL状态机的封装.是与OpenGL交互的类
inline void applyModelViewMatrix(const osg::RefMatrix* matrix)
        {
            if (_modelView!=matrix)
            {
                if (matrix)
                {
                    _modelView=matrix;
                    glLoadMatrix(matrix->ptr());
                }
                else
                {
                    _modelView=_identity;
                    glLoadIdentity();
                }
            }
        }

它是直接使用glLoadMatrix(matrix)进行载入矩阵的.因此它的转置刚好适应了OpenGL列优先的模式.

你只需牢记 在OSG当中变换的步骤则是左乘操作(全局坐标系)..即左边的是先执行变换的.

谈完如上的那些之后.我们现在来看MatrixTransform 和PositionAttitudeTransform.

参考坐标系有三种
            RELATIVE_RF,    //全局 相对 ()
            ABSOLUTE_RF,  //局部  绝对 ()
            ABSOLUTE_RF_INHERIT_VIEWPOINT   //基于视点一个局部坐标系.很少用到.

MatrixTransform 故名 矩阵变换节点.在位于它的节点之下的节点都将按照这它的矩阵变换来进行模型变换操作.因此 MatrixTransform的主要功能之一就是提供模型变换操作..你只要根据你所需要的设置其模型矩阵就行.
即执行 setMatrix() 因此.查看计算当前World矩阵的方法就可以很清晰的明白其最后结果就是:

如果是相对的.那么 先执行自身的变换,在执行父节点的变换操作.这类似OpenGL中后写的变换是先执行的一样(全局坐标系考虑)
否则是绝对的,那么当前矩阵就是自身矩阵

bool MatrixTransform::computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*) const
{
    if (_referenceFrame==RELATIVE_RF)
    {
        matrix.preMult(_matrix);
    }
    else // absolute
    {
        matrix = _matrix;
    }
    return true;
}

PositionAttibuteTransform 就是位置姿态节点..即我们只可以调整该节点的所有孩子的位置以及姿态.,我们也先来看一下它的矩阵变换:

bool PositionAttitudeTransform::computeLocalToWorldMatrix(Matrix& matrix,NodeVisitor*) const
{
    if (_referenceFrame==RELATIVE_RF)
    {
        matrix.preMultTranslate(_position);
        matrix.preMultRotate(_attitude);
        matrix.preMultScale(_scale);
        matrix.preMultTranslate(-_pivotPoint);
    }
    else // absolute
    {
        matrix.makeRotate(_attitude);
        matrix.postMultTranslate(_position);
        matrix.preMultScale(_scale);
        matrix.preMultTranslate(-_pivotPoint);
    }
    return true;
}

PositionAttibuteTransform 的矩阵变换顺序的固定的.可以说是MatrixTransform的一个特例.,操作顺序我就不在详谈了.因为它的功能就是为了实现姿态和位置.还有缩放等.
因此 setPivotPoint 将使得之后的变换将会基于此平移操作执行.  

那么实现一个例子来观察他们的效果: 下面的例子则是
<1> 使用PositionAttitudeTransform 设置左边的牛. 位置位于(-10,0,0) 姿态为绕z轴旋转90度.
<2> 使用MatrixTransform 设置右边的牛,  先执行平移操作(10,0,0) 在绕z轴旋转60度 因此使得这只牛偏屏幕内部一点.(你画个坐标轴 按全局思路演示 则就知道牛在上面位置了.!)

osg::Node* createTrans()
{
    /** declare a root node*/
    osg::Group* root = new osg::Group;
    /** declare a Position Node*/
    osg::PositionAttitudeTransform* posCow = new osg::PositionAttitudeTransform;
    root->addChild(posCow);
    /** declare a Matrix Node*/
    osg::MatrixTransform* matrixCow  = new osg::MatrixTransform;
    root->addChild(matrixCow);

    osg::Node* cow = osgDB::readNodeFile("cow.osg");

    /** 
        When use Position Node and the ReferenceFrame is RELATIVE_RF
        the matrix is Compute  Trans(-pivot) * scale * Rotate * Trans(Pos)
        here the pivot and scale is default,so it means that make rotate firstly.
    */
    posCow->addChild(cow);
    osg::Quat quat;
    quat.makeRotate(osg::PI_2,osg::Vec3(0.0,0.0,1.0));
    posCow->setAttitude(quat);
    posCow->setPosition(osg::Vec3(-10,0.0,0.0));

    /**
        when use Matrix Node  you can set the matrix what you want.
        here , it  make trans firstly and then make rotate.
    */
    matrixCow->addChild(cow);
    quat.makeRotate(osg::DegreesToRadians(60.0),osg::Vec3(0.0,0.0,1.0));
    matrixCow->setMatrix(osg::Matrixd::translate(osg::Vec3(10.0,0.0,0.0))*osg::Matrixd::rotate(quat));

    return root;
}

 

 

以上是关于OSG世界坐标转屏幕坐标(转载)的主要内容,如果未能解决你的问题,请参考以下文章

Unity中的坐标系--屏幕转世界坐标

将世界坐标转成NGUI坐标

将窗口坐标转换为屏幕坐标??

OSG坐标系统

OpenSceneGraph几个重要功能节点练习

Unity UI跟随3D物体,世界坐标转UI坐标