chdoca的个人博客分享 http://blog.sciencenet.cn/u/chdoca

博文

关于opengl坐标变换的一点体会

已有 6640 次阅读 2012-3-18 19:41 |个人分类:学习心得|系统分类:科研笔记| OpenGL

    这些天刚刚接触opengl编程,感觉在坐标转换的地方理解起来有点难度,下午从网上找了一下红宝书中介绍的nate robin示例程序,对其中的transformation.c研究了一下,通过不断改变参数的设置,结合显示的结果,终于对各种坐标变换的关系屡清了一点思路,现在结合transformation.c介绍一下我对opengl坐标变换的理解,希望能对有同样疑惑的朋友有所帮助。
    首先介绍一下opengl四种坐标变换的含义。模型变换:用于调整物体的大小、位置,模型边换之后得到的物体坐标是相对于全局坐标系统的。视图变换:用于设置相机的位置、相机轴线的方向以及拍摄的方向。模型变换和视图变换统称为模型视图变换(modelview),经过模型视图变换之后的坐标是视觉系统内的坐标,其实是模型相对于相机的坐标,因为这里是模型和视图的一种相对关系,因此模型变换和视图变换具有一定的等价性和可转换性。接着是投影变换,投影变换的效果是建立一个视景体,使物体位于其中,对视景体外的物体部分进行截断,投影变换之后的坐标反应的是物体在视景体内的位置属性,比如同样大小的面(在全局坐标系统中),靠近视景体前端的占其相对应的截面的比例更大,因此在变换后的面积也更大。最后是视口变换,其作用是将确定最终图像的大小,并将帧缓冲区域内的数据转变为能显示在屏幕上的像素。由于变换是通过左乘矩阵完成的,因此实际坐标变换的顺序和代码中出现的顺序是相反的。一般先设置模型视图变换,再设置投影变换,最后是视口变换,并且由于改变窗口只对投影和视口变换有影响,因此常将这两种变换放在reshape函数里。

    transformation.c是将汽车模型的立体图显示在窗口中,而且做成了交互式的界面 。程序包括了4个主要部分:窗口(window)部分、world-space部分、screen-space部分和command-space部分。world子窗口用于显示汽车模型和相机、视景体的位置关系,screen子窗口显示汽车模型,command子窗口显示参数,便于交互式更改以观效果。当window的大小或位置发生改变时,main-reshape函数被调用,main-reshape再改变每个子窗口的reshape参数,使其被回调。window、screen和command的display和reshape函数比较简单,就是对种变换按顺序进行设置,在这不多冗述,主要是解释一下world-space的reshape和display。

        void world_reshape(int width, int height)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (GLfloat)width/height, 0.01, 256.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -5.0);                            //world-space的四种变换
    glRotatef(-45.0, 0.0, 1.0, 0.0);
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHT0);
}

void  world_display(void)
{
      .......
    invert(modelview, inverse);         //求screen-space模型视图变换的逆
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   
    if (world_draw) {
        glEnable(GL_LIGHTING);
        glPushMatrix();
        glMultMatrixd(inverse);
        glLightfv(GL_LIGHT0, GL_POSITION, pos);
        glPopMatrix();
        drawmodel();

        glDisable(GL_LIGHTING);
    }
   
    glPushMatrix();
   
    glMultMatrixd(inverse);
   
    glLightfv(GL_LIGHT0, GL_POSITION, pos);
    
        glPushMatrix();

    .............

 /*draw the axis and eye vector */
.......................
         glPopMatrix();
    invert(projection, inverse);       //求screen-space投影变换的逆

    glMultMatrixd(inverse);
    ..................
    /* draw the viewing frustum */
     ............................  
    glPopMatrix();
    glutSwapBuffers();
}

    world-space画的是screen-space中汽车模型与相机、视景体的位置关系,因此,汽车模型、相机(用三维坐标系表示)和视景体就相当于world-space中的“模型”。在world-reshape函数中设置的是world空间中的四种变换,这相当于最外层的变换,我们可以先不管,等将模型“画”好了再说。

       world-display函数就是用来画模型的,及汽车、三维坐标系和视景体。invert函数是用来求逆变换的,逆变换矩阵保存在inverse数组中。modelview矩阵式screen-space中的模型视图变换矩阵。对它求逆得到inverse,并用inverse来变换三维坐标系模型的坐标,其实是确定了三维坐标系模型和汽车模型的相对关系:screen-space中的modelview一改变便会通过invert函数传递到world-space中,三维坐标系模型便会相对汽车模型做相反的变化。projection矩阵是screen-space中投影变换矩阵,对它求逆并作用到world-space视景体模型上,产生视景体的立体效果(其实可以这样理解:在screen-space中同样大小的两个面,靠近相机的面显得更大,因此在world-space中逆变换之后,靠近相机模型的视景体的面显得更小)。在projection逆矩阵基础上再左乘modelview的逆矩阵,就将视景体模型和三维坐标模型绑定在了一起。当screen-space中modelview变化时,在world-space中三维坐标模型和视景体模型就会相对汽车模型做相反的运动。

     模型“画”完之后,再对world-space进行四种变换即可,这里将模型相对y轴旋转45度是为了更直观。

     再次提醒一下,模型坐标变换的顺序和代码的顺序是相反的。红宝书中使用全局坐标系统和局部坐标系统的概念,局部坐标系统是固定在模型中心的,随模型的变换而变化,根据局部坐标系统和 glPopMatrix(), glPushMatrix()函数,以及模型之间的相对位置关系,可以使程序变得简洁很多。

transformation.exe运行结果



https://wap.sciencenet.cn/blog-691244-549059.html


下一篇:C++Primer学习笔记
收藏 IP: 159.226.21.*| 热度|

0

该博文允许注册用户评论 请点击登录 评论 (0 个评论)

数据加载中...
扫一扫,分享此博文

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-4-28 05:37

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部