博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OpenGL的视图变换
阅读量:5862 次
发布时间:2019-06-19

本文共 4173 字,大约阅读时间需要 13 分钟。

hot3.png

OpenGL 中场景进行变换,要经历一些过程:视图变换 à 模型变换 à 投影变换,然后到了窗口坐标。这几个变换开始的时候把我搞很混,这几天整理一下。

       一般书上把这几个变换用照相机类比,其实每个变换都是产生着一个 4x4 矩阵,然后与当前矩阵 (Current Matrix) 相乘,得到一个坐标变换矩阵,最后把世界坐标系(欧式空间)中的物体变换到屏幕坐标系中。这里梳理一下概念:

       1 、视图变换( VIEW Transformation ):它类似将照相机指向物体,即确定视点(观察点)的位置和观察方向。一般用的函数为 glu 封装的函数:

void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez,  --------- 观察点

       GLdouble centrex, GLdouble centrey, GLdouble centrez,  -- 视线方向:从 eye 指向 centre

       GLdouble upx, GLdouble upy, GLdouble upz ------------ 视图体自下而上的方向

 )

       这个函数会产生一个视图矩阵,并右乘到当前矩阵上。模型变换通常发生在模型变换之前。其实,视图变换也是通过平移和旋转得到的,观察位置与物体位置之间是个相对的状态,我们也把视图变换和模型变换统一成一个变换,产生一个矩阵:模型视图变换矩阵。

       2 、模型变换 (MODEL Transformation) :它确定模型的位置和方向,对模型进行旋转、平移和缩放。用到三个子函数:glTranslate*(x, y, z)  glRotate*(x, y, z)  glScale*(x, y, z) 。每个函数都会产生一个矩阵,并右乘当前矩阵。

       3 、投影变换( PROJECTION Transformation ):产生一个六面的视图体,把视图体以外的场景剪裁掉,把视图体内的物体、场景作为绘制对象,让“照相机拍摄”。两种投影方式,两个投影函数: glFrustum(left, right, bottom, top, near, far) 

glOrtho(left, right, bottom, top, near, far )

这两个函数的参数非常对称,都是构筑了一个六面体,形成可视范围。它们都产生一个矩阵,并左乘当前矩阵。(当然,还有 glu的两个函数)。

      

       要理解整个过程,关键在理解当前变换矩阵 CTM ,(简称为 C )。它是一个状态概念,应用到 OpenGL 流水线中的每一个定点: P = C*P’ 。这条等式是对同一个点在两个坐标系体统之间进行转换,从右边的坐标系下的坐标( P’ )转换到左边的坐标系下的坐标( P )。而矩阵 C  4x4 的齐次坐标矩阵,它都蕴含着一个局部坐标系信息:以右边坐标系为参考坐标系统,左边坐标系的位置和方向。

       用手工定义一个矩阵,如下(按 OpenGL 矩阵方式定义。与数学定义矩阵的方式转置):

       CTM[16] = { a0, a1, a2, a3,         // x 轴的方向向量

                        a4, a5, a6, a7,          // y 轴的方向向量

                        a8, a9, a10, a11,              // z 轴的方向向量

                        a12, a13, a14, a15    // 原点的位置

                            }

      

       再来考察当前变换矩阵 CTM ,它是在 OpenGL 流水线中一个模型视图矩阵和一个投影矩阵的复合。 CTM = P*C*M 。(注意到上面提到的左乘右乘了吗?)

 aa.bmp
04150120_h0qF.jpg

我们来分析一个简单的例子: 

 

 

 1 04150120_n4Mi.gif #define  NUM 0.70710678118654746 

 2 04150120_n4Mi.gif // 注意这个矩阵是正交的,没有正交就用,好像有放缩作用 
GLfloat Tmat1[16] = { NUM, NUM, 0.0, 0.0,
                    -NUM, NUM, 0.0, 0.0,
                     0.0, 0.0, 1.0, 0.0,
                     0.0, 0.0, 0.0, 1.0};

GLfloat Tmat2[16] = { 1.0, 0.0, 0.0, 0.0,

                      0.0, 1.0, 0.0, 0.0,
                      0.0, 0.0, 1.0, 0.0,
                      1.0, 0.0, 0.0, 1.0,
                        }; 
 7 04150120_n4Mi.gif void  setupRC( void )
 8 04150120_MIIJ.gif {
 9 04150120_OHKU.gif    glClearColor( 0.0f ,  0.0f ,  0.0f ,  1.0f );
10 04150120_OHKU.gif    glShadeModel(GL_FLAT);
11 04150120_lBee.gif
12 04150120_n4Mi.gif 
13 04150120_n4Mi.gif void  RenderScene( void )
14 04150120_MIIJ.gif {
15 04150120_OHKU.gif    printf( " RenderScene04150120_YHCi.gif\n " );   
16 04150120_OHKU.gifglClear(GL_COLOR_BUFFER_BIT);
17 04150120_OHKU.gifglColor3f( 0.0f ,  1.0f ,  1.0f );
18 04150120_OHKU.gif    glMatrixMode(GL_MODELVIEW);
19 04150120_OHKU.gif    glLoadIdentity();
20 04150120_OHKU.gif    gluLookAt( 0.0 ,  0.0 ,  5.0 ,         //  view point 
21 04150120_OHKU.gif                0.0 ,  0.0 ,  0.0 ,         //  focus point 
22 04150120_OHKU.gif                0.0 ,  1.0 ,  0.0 );        //  up vector 
23 04150120_OHKU.gif 
24 04150120_OHKU.gif   glutSolidCube( 0.5 );                 //  原点的参考位置 
25 04150120_OHKU.gif     glMultMatrixf(Tmatr1);                 // 这个矩阵的动作和下面的两个变换是一样的。
               glMultMatrixf(Tmatr2);
26 04150120_OHKU.gif //     glRotatef(45.0, 0.0, 0.0, 1.0);
27 04150120_OHKU.gif //     glTranslatef(3.0, 0.0, 0.0); 
28 04150120_OHKU.gif     glutSolidCube( 1.0 );
29 04150120_OHKU.gif 
30 04150120_OHKU.gif    glutSwapBuffers();
31 04150120_lBee.gif
32 04150120_n4Mi.gif 
33 04150120_n4Mi.gif void  ChangeSize( int  w,  int  h)
34 04150120_MIIJ.gif {
35 04150120_OHKU.gif    printf( " ChangeSize04150120_YHCi.gif\n " );    // 从这里看出,是先调用ChangeSize()的
36 04150120_OHKU.gif    GLfloat nRange  =   10.0f ;
37 04150120_OHKU.gif 
38 04150120_OHKU.gif     if (h  ==   0 )
39 04150120_OHKU.gif        h  =   1 ;
40 04150120_OHKU.gif    GLfloat fRatio  =  (GLfloat)w  /  (GLfloat)h;
41 04150120_OHKU.gif 
42 04150120_OHKU.gif    glMatrixMode(GL_PROJECTION);
43 04150120_OHKU.gif    glLoadIdentity();
44 04150120_OHKU.gif 
45 04150120_OHKU.gif     if (w  <=  h)
46 04150120_OHKU.gif        glOrtho( - nRange, nRange,  - nRange  /  fRatio, nRange  /  fRatio,  1.0 , nRange);
47 04150120_OHKU.gif     else 
48 04150120_OHKU.gif        glOrtho( - nRange  *  fRatio, nRange  *  fRatio,  - nRange, nRange,  1.0 , nRange);
49 04150120_OHKU.gif 
50 04150120_OHKU.gif    glViewport( 0 ,  0 , w ,h);
51 04150120_OHKU.gif 
52 04150120_OHKU.gif    glMatrixMode(GL_MODELVIEW);
53 04150120_OHKU.gif    glLoadIdentity();
54 04150120_lBee.gif
55 04150120_n4Mi.gif 
56 04150120_n4Mi.gif int  main( int  argc,  char *  argv[])
57 04150120_MIIJ.gif {
58 04150120_OHKU.gif    glutInit( & argc, argv);
59 04150120_OHKU.gif    glutInitDisplayMode(GLUT_RGB  |  GLUT_DOUBLE);
60 04150120_OHKU.gif    glutInitWindowSize( 800 ,  600 );
61 04150120_OHKU.gif    glutCreateWindow( " example04150120_YHCi.gif " );
62 04150120_OHKU.gif 
63 04150120_OHKU.gif    glutReshapeFunc(ChangeSize);
64 04150120_OHKU.gif    glutDisplayFunc(RenderScene);
65 04150120_OHKU.gif 
66 04150120_OHKU.gif    setupRC();
67 04150120_OHKU.gif 
68 04150120_OHKU.gif    glutMainLoop();
69 04150120_OHKU.gif 
70 04150120_OHKU.gif    std::cout  <<   " Hello world! "   <<  std::endl;
71 04150120_OHKU.gif     return   0 ;
72 04150120_lBee.gif
73 04150120_n4Mi.gif

 glRotatef(45.0, 0.0, 0.0, 1.0)   

glTranslatef(3.0, 0.0, 0.0);  

这两个变换,可以看成:

       glMultMatrixf(R);

       glMultMatrixf(T);

R,T 都是右乘到 CTM  CTM = CTM * R * T

对模型变换的理解有两种:

1、在全局固定坐标系下,对物体进行变换。这时候,我们要以相反的顺序来考虑代码中的变换函数了,它的实际过程是这样 P = CTM *( R*(T* p’)) 

首先、对物体进行平移,平移到坐标( 3.0, 0.0, 0.0 )。  然后,把物体相对原点绕z轴旋转45度。

2、物体捆绑在局部坐标系下,所有的变换都是坐标系进行的。这时,我们用顺序来看这个变换。

glRotatef(45.0, 0.0, 0.0, 1.0) 产生一个齐次矩阵 R( 这可是代表一个局部坐标系哦 )   ,即局部坐标系 R 相对刚才开始的坐标系 I (单位矩阵)作了旋转变换,绕旋转了45度。

glTranslatef(3.0, 0.0, 0.0) 产生一个齐次矩阵 T (也是代表了一个局部坐标系),相对 R 坐标系沿x轴( R 系)平移了3个单位,得到了自己的局部坐标系 T 

最后在这个局部坐标系 T 下画了 Cube 

代码中的 Tmat = R * T ,它也是从 T 坐标系变换到 R 坐标系,再变换到最后的模型视图的世界坐标系。

 

 

后注:

       对坐标系的几何变换是  既采用基于齐次坐标的矩阵表达形式 ! 又在欧氏几何的 Cartesian 坐标系下以对其进行说明性的定义 . 由于齐次坐标是射影几何的语言工具 ! 前者表明几何变换的表达是基于射影几何的后者则带有欧氏几何色彩  ,所以对它的表述清晰统一的表述比较难。本文写的也比较零散,有语焉不详、理解错误指出,请多多指正!

转载于:https://my.oschina.net/u/1469992/blog/233026

你可能感兴趣的文章
shader
查看>>
【javascript】九宫格抽奖组件设计
查看>>
python URLObject url处理模块
查看>>
Fiddler 抓包工具总结-bpafter
查看>>
Mac下docker搭建lamp本地开发环境
查看>>
Spark学习之路 (一)Spark初识
查看>>
建立组织级过程性能基线的注意事项
查看>>
python MQTT 出现TypeError: payload must be a string, bytearray, int, float or None.
查看>>
模型融合
查看>>
gcc编译选项【转】
查看>>
【spring boot】【mybatis】spring boot中mybatis打印sql语句
查看>>
Android App优化之ANR详解
查看>>
滴水不漏
查看>>
WPF控件深拷贝:序列化/反序列化
查看>>
Java的优先级任务队列的实践
查看>>
thinkphp5开发规范(加强复习之前的)
查看>>
Linux手工添加swap
查看>>
PowerTCP FTP for .NET 在线e文文档
查看>>
SpirngBoot之整合Swagger2
查看>>
linux grep 取出特定字符串并统计个数
查看>>