您的位置:首页 > 运维架构

OpenGL坐标转换总结

2016-06-15 19:40 351 查看
前面整理过一个,不过后来感觉不是很对,这里重新写一下。先解释一下这个问题,在OpenGL编程中,经常会需要与用户的交互,比如对视图进行指定点旋转,获取模型坐标点等。而这些操作最方便的就是通过鼠标进行操作,但鼠标只能获得屏幕坐标,那么如何转换到OpenGL世界坐标就成了一个亟待解决的问题。

一、理论基础

主要需要的是一些OpenGL观察流程相关知识,但也不是十分必要,大致了解即可。

二、屏幕坐标转换成世界坐标

//
数据结构
struct Point3D
{
    double x;
    double y;
    double z;
};
// 函数体
Point3D CMultiViewerView::WinToGL(CPoint winpt)
{
    Point3D glpt;
    GLint viewport[4];   
    GLdouble modelview[16];   
    GLdouble projection[16];   
    GLfloat winX, winY, winZ;   
    GLdouble posX, posY, posZ;
    GLdouble last_posX, last_posY, last_posZ;
    GetGLContext();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glPushMatrix();    
    //缩放、平移、旋转等变换(不要加这些!!)
    // glMultMatrixf(m_mv);
    glGetIntegerv(GL_VIEWPORT, viewport); // 得到的是最后一个设置视口的参数  
    glGetDoublev(GL_MODELVIEW_MATRIX, modelview);   
    glGetDoublev(GL_PROJECTION_MATRIX, projection);   
    glPopMatrix();   
    winX = winpt.x;   
    winY = viewport[3] - (float)winpt.y;   
    glReadPixels((int)winX, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);   
    gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
    glpt.x = posX;
    glpt.y = posY;
    glpt.z = posZ;
    return glpt;
}
上面的函数的输入参数CPoint winpt可以由MFC的鼠标消息响应函数直接得到,当然,用其他语言应该也有相应的方法得到。

注意,网上有人认为需要增加视图已经做过的变换,个人认为不是很必要,因为modelview包含了需要的一切信息。

上面函数的关键语句是

 gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);

这就是通过模型变换矩阵,投影矩阵,视口矩阵,由窗口坐标得到GL世界坐标的方法。

三、世界坐标转换成屏幕坐标

语句类似,关键几句为

glPushMatrix();
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);    // 视图矩阵
glGetDoublev(GL_PROJECTION_MATRIX, projection); // 投影矩阵
glGetIntegerv(GL_VIEWPORT, viewport);            // 视口
glPopMatrix();
gluProject(    (GLdouble) x,
        (GLdouble) y,
        (GLdouble) z,
        modelview,
        projection,
        viewport,
        &posX,
        &posY,
        &posZ);
四、计算固定点经过模型变换后坐标

这也是一个常见的问题,这并不需要什么特别的函数,只要将modelview乘以固定点的齐次坐标即可,对于三维空间中的点,其齐次坐标为[x, y, z, 1],另外前面说过,modelvew是一个16个元素的数组,就是一个列序的4x4矩阵,因此正好可以进行矩阵相乘。

struct Point3D
{
    double x;
    double y;
    double z;
};
glGetFloatv( GL_MODELVIEW_MATRIX, m_mv);

Point3D CMecViewerView::TransPoint(Point3D centerpt)
{
    Point3D transedpt;
    transedpt.x = m_mv[0]*centerpt.x + m_mv[4]*centerpt.y + m_mv[8]*centerpt.z + m_mv[12]*1;
    transedpt.y = m_mv[0+1]*centerpt.x + m_mv[4+1]*centerpt.y + m_mv[8+1]*centerpt.z + m_mv[12+1]*1;
    transedpt.z = m_mv[0+2]*centerpt.x + m_mv[4+2]*centerpt.y + m_mv[8+2]*centerpt.z + m_mv[12+2]*1;
    return transedpt;
}
上面的m_mv获取是用

版权声明:本文为博主原创文章,未经博主允许不得转载。

[cpp] view
plain copy

GLint    viewport[4];   

 GLdouble modelview[16];   

 GLdouble projection[16];   

 GLfloat  winX, winY, winZ;   

 GLdouble posX, posY, posZ;   

  

 glPushMatrix();  

   

 // 变换要绘图函数里的顺序一样,否则坐标转换会产生错误  

 glScalef(m_srtMatrix[0], m_srtMatrix[1], m_srtMatrix[2]); // 缩放、平移、旋转变换  

 glRotatef(m_srtMatrix[3], 1.0f, 0.0f, 0.0f);  

 glRotatef(m_srtMatrix[4], 0.0f, 1.0f, 0.0f);  

 glRotatef(m_srtMatrix[5], 0.0f, 0.0f, 1.0f);  

 glTranslatef(m_srtMatrix[6], m_srtMatrix[7], m_srtMatrix[8]);  

  

  

 glGetIntegerv(GL_VIEWPORT, viewport); // 得到的是最后一个设置视口的参数  

 glGetDoublev(GL_MODELVIEW_MATRIX, modelview);   

 glGetDoublev(GL_PROJECTION_MATRIX, projection);   

  

 glPopMatrix();  

  

 winX = x;   

 winY = screenHeight - y;  

 glReadPixels((int)winX, (int)winY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);   

 gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);  

http://www.opengl.org/sdk/docs/man/xhtml/gluUnProject.xml  gluUnProject()

http://www.opengl.org/sdk/docs/man/xhtml/gluProject.xml  gluProject()

http://blog.csdn.net/abcdef8c/article/details/6716737   屏幕坐标到opengl世界坐标转换
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: