doing5552

记录每日点滴,不枉人生一世

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  73 Posts :: 0 Stories :: 94 Comments :: 0 Trackbacks

公告

常用链接

留言簿(24)

我参与的团队

最新随笔

搜索

  •  

积分与排名

  • 积分 - 452045
  • 排名 - 47

最新随笔

最新评论

阅读排行榜

评论排行榜

乱弹OpenGL中的矩阵变换(上)


在前面的日志(Shadow Volume 阴影锥技术之探Ⅲ )中,自己稍微提及了NEHE的"3D矩阵求逆"方法之高,并谈了谈自己的一点拙略理解。呵呵,然后,既然如此,一不做二不休,在本篇中得继续乱弹一下下,关于OpenGL矩阵的理解。因为我实在不知道会不会在哪儿就把你忽悠+误导了(但还是期盼你的信任),请看官自重哈哈。
这里有一句,我认为,最能够消解头脑中的云雾的话:OpenGL中所有的变换,都是在变换坐标系。
你还好吗?你还能看见你眼前书桌上那个苹果吗?你把它向右边移动10厘米看看?移好了吗?想一想,假如你眼前就是OpenGL的一个渲染窗口的话,苹果是不是往x轴正方向移动了10单位(假设单位:厘米)?恩,你现在所感受到的真实告诉你:苹果确实不再在原位置,而是向右移了10厘米到了一个新的位置。我想说的是,当你完全迈进3D图形学殿堂后,请不要再那么轻易相信的眼睛所感受到的真实——它是真实,但不是真实的全部。在你刚才一瞬间想象出的OpenGL渲染窗口里,苹果没有移动,它一直在那里,一直....而移动的是整个空间,整个世界,包括书桌,包括你,包括你的眼睛!
在OpenGL的那个世界中,最初存在着几个重叠的空间。有模型空间,有世界空间,视图空间,屏幕空间等。每个空间实质就是一个坐标系(统)——坐标系统当然就有坐标轴。在最初的这个时刻,也许整个OpenGL世界也就只有这一套坐标轴了:恩,一套。世界永远只有一个,但是依附于这个世界的空间则平行地同时存在——实体(例如坐标轴,苹果)唯一,而实体的表示(各个空间中对应的坐标轴,苹果)则多样。我是这么理解的,OpenGL世界。
最初的OpenGL世界只有一套看不见的坐标轴,然后,用户说:苹果!于是世上就有了苹果。苹果轻轻地出现在映射着这个世界的各个空间中——就在那个万物之源的坐标原点上。原点与苹果的“中心”对应(当然“中心”不一定指苹果中间,它由上帝...不,用户在制造这个苹果时决定。确切地说,我们在画物件(或者直接叫:模型)时给予这些东西的各个glVertex3顶点(坐标x,y,z),它们的存在必然以位置(0,0,0)为标尺——这个位置就是此物件的“中心”)。就在苹果出现的此瞬间,模型空间(Model-Coordination,也称Local-Corrdination)安静了,此刻的整个世界的一切如同屏幕截图般被保存起来,储存在模型空间——永远以当前这个“中心”为原点,以当前这些坐标(x,y,z)为苹果各顶点的"模型坐标系坐标"。
 
//1.用户创世第1天,说:苹果! 世上便有了苹果---苹果在模型空间(local 空间)被永恒描述
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
//1.用户创世第1天,说:苹果! 世上便有了苹果---苹果在模型空间(local 空间)被永恒描述
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}

当然,苹果出现在模型空间坐标系统原点,必然也就出现在其他空间坐标系统的原点,此时各空间的坐标系是重合的,只不过模型空间被固定了,其他空间还没而已。苹果怎么移动到别处呢?恩,编程的时候可以这么问,但当你正在了解OpenGL世界的时候(如现在),这个问法很不靠谱。你看上面的代码(glVertex3f(A); glVertex3f(B)....)这里点A,B...不是给定了吗?就算是变量,在“画点”的时刻变量的值也是给定的呀。是的,变的不该是苹果,而是坐标系,准确地理解,是世界空间(World-Coordination)的那个坐标系要变,在原先与模型空间坐标系重合的基础上变。这个变的过程,叫模型变换(Model-Translation)。具体来说就是用一个表示“转动/移动/缩放”的矩阵左乘苹果的各个顶点坐标,得出的结果(是一些不同的坐标)作为苹果对应顶点在世界空间坐标系中的位置坐标。诶?苹果变了吗?可以这么说,苹果的“坐标”还是原来那些A.B...但对应于世界坐标系的“位置”变化了。
这里确实是很容易迷糊,默念吧:OpenGL中所有的变换,都是在变换坐标系。不是苹果右移了10厘米,而是世界坐标系左移了10厘米!假设苹果中心最初恰就是出现在模型空间并与模型坐标系原点重合,然后考虑以此为初状态的世界空间,在用户做了模型变换(向苹果中心点所在之坐标(0,0,0),左乘一个表示右移10厘米的模型变换矩阵)后,这个坐标由(0,0,0)变成(10,0,0),相当于坐标系原来的虚拟坐标(10,0,0)变成现在的(0,0,0)。看,坐标系(由无限的虚拟坐标构成)左移10厘米!我想说,这才是模型变换(Model-Translation)的真正所为。与之前一样,当一切变换完成,结果被截屏存入世界空间。世界空间的动荡结束,从此定型。
 
//2.用户创世第2天,说:苹果右移! 于是世界坐标系便左移了,结果存入世界空间
glMatrixMode(GL_MODEL);//表示接下来要作“模型转换”
glTranslatef(10,0,0);//相当于一个平移矩阵
 
//1.用户创世第1天,说:苹果! 世上便有了苹果---苹果在模型空间(local 空间)被永恒描述 
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
//2.用户创世第2天,说:苹果右移! 于是世界坐标系便左移了,结果存入世界空间
glMatrixMode(GL_MODEL);//表示接下来要作“模型转换”
glTranslatef(10,0,0);//相当于一个平移矩阵

//1.用户创世第1天,说:苹果! 世上便有了苹果---苹果在模型空间(local 空间)被永恒描述
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
接下来发生的事情跟之前一样,只是从模型空间---(模型变换)---》世界空间的关系,改成世界空间---(视图变换 View Translation)---》视图空间的关系而已。请好好再模拟一次:一模一样的过程,这次的移动所需要的左乘矩阵(左乘刚才保存的模型转换结果嘛)由相机(眼睛,视线)的设置提供,结果存入视图空间而已。
 
//3.用户创世第3天,说:我是主角! 于是他拥有了第一人称视觉,结果存视图空间
glMatrixMode(GL_VIEW);//表示接下来要作“视图转换” 
gluLookat(eye,look,up)//也相当于一个平移矩阵 
 
//2.用户创世第2天,说:苹果右移! 于是世界坐标系便左移了,结果存入世界空间 
glMatrixMode(GL_MODEL);//表示接下来要作“模型转换” 
glTranslatef(10,0,0);//相当于一个平移矩阵 
 
//1.用户创世第1天,说:苹果! 世上便有了苹果---苹果在模型空间(local 空间)被永恒描述  
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
//3.用户创世第3天,说:我是主角! 于是他拥有了第一人称视觉,结果存视图空间
glMatrixMode(GL_VIEW);//表示接下来要作“视图转换”
gluLookat(eye,look,up)//也相当于一个平移矩阵

//2.用户创世第2天,说:苹果右移! 于是世界坐标系便左移了,结果存入世界空间
glMatrixMode(GL_MODEL);//表示接下来要作“模型转换”
glTranslatef(10,0,0);//相当于一个平移矩阵

//1.用户创世第1天,说:苹果! 世上便有了苹果---苹果在模型空间(local 空间)被永恒描述 
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
噢,接下来是:视图空间---(投影变换)---》屏幕空间。投影变换的变换手法与之前的不同,屏幕空间以视图空间结果为基础,先用一个平头锥体(视景锥)把视线范围外的空间割了(裁剪),再把投影到一个可以覆盖渲染屏幕窗口的矩形上(具体做法是,XYZ除以隐含的齐次坐标W,然后舍弃深度Z),保存为屏幕空间——一个平面,让用户所能感悟到这一切不过显示器屏幕一部分像素的把戏。当然,最后的坐标还要隐映射为渲染窗口的客户区坐标(原点在窗口左上角,Y轴下X轴右的平面坐标),算是走出了OPENGL世界。
 
//4.用户创世第4天,说:到显示屏来吧! 世界便是"平"的了.最后得屏幕空间
glViewport(0,0,width,height);//设置那个"视景区矩形"大小
glMatrixMode(GL_PROJECTION));//表示接下来要作“投影转换” 
gluPerspective(fov,aspect,near,far);//视景体应用
 
//3.用户创世第3天,说:我是主角! 于是他拥有了第一人称视觉,结果存视图空间 
glMatrixMode(GL_VIEW);//表示接下来要作“视图转换”  
gluLookat(eye,look,up)//也相当于一个平移矩阵  
 
//2.用户创世第2天,说:苹果右移! 于是世界坐标系便左移了,结果存入世界空间  
glMatrixMode(GL_MODEL);//表示接下来要作“模型转换”  
glTranslatef(10,0,0);//相当于一个平移矩阵  
 
//1.用户创世第1天,说:苹果! 世上便有了苹果---苹果在模型空间(local 空间)被永恒描述   
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
//4.用户创世第4天,说:到显示屏来吧! 世界便是"平"的了.最后得屏幕空间
glViewport(0,0,width,height);//设置那个"视景区矩形"大小
glMatrixMode(GL_PROJECTION));//表示接下来要作“投影转换”
gluPerspective(fov,aspect,near,far);//视景体应用

//3.用户创世第3天,说:我是主角! 于是他拥有了第一人称视觉,结果存视图空间
glMatrixMode(GL_VIEW);//表示接下来要作“视图转换” 
gluLookat(eye,look,up)//也相当于一个平移矩阵 

//2.用户创世第2天,说:苹果右移! 于是世界坐标系便左移了,结果存入世界空间 
glMatrixMode(GL_MODEL);//表示接下来要作“模型转换” 
glTranslatef(10,0,0);//相当于一个平移矩阵 

//1.用户创世第1天,说:苹果! 世上便有了苹果---苹果在模型空间(local 空间)被永恒描述  
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}

事实上OpenGL的glMatrixMode函数里没有GL_MODEL和GL_VIEW这两种设值。上面提到过,模型变换和视图变换其实是同一种处理,而且视图变换只由相机控制,有则有,无则默认。因此OpenGL直接就用GL_MODELVIEW一起转换了。简洁是简洁,但是这样一来用户就不知道世界空间里的坐标系什么时候改变了,也难得到物体在世界坐标系下的位置坐标了(事实上还是有办法的,不过搞复杂了,见以后的博文啦)。
 
glViewport(0,0,width,height);//设置那个"视景区矩形"大小 
 
glMatrixMode(GL_PROJECTION));//表示接下来要作“投影转换”  
glLoadIdentity();
gluPerspective(fov,aspect,near,far);//视景体应用 
 
gluLookat(eye,look,up)//控制整个视景体   
 
glMatrixMode(GL_MODELVIEW);//表示接下来要作“模型视图转换”  
glLoadIdentity(); 
glTranslatef(10,0,0);//相当于一个平移矩阵   
 
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
........
glViewport(0,0,width,height);//设置那个"视景区矩形"大小

glMatrixMode(GL_PROJECTION));//表示接下来要作“投影转换” 
glLoadIdentity();
gluPerspective(fov,aspect,near,far);//视景体应用

gluLookat(eye,look,up)//控制整个视景体  

glMatrixMode(GL_MODELVIEW);//表示接下来要作“模型视图转换” 
glLoadIdentity();
glTranslatef(10,0,0);//相当于一个平移矩阵  
 
DrawApple() //{glBegin();glVertex3f(A);glVertex3f(B)....glEnd()}
........
此外,每次变换不是以之前保存的那个空间的位置信息为基础吗?这要用到glLoadIdentity()函数,初始化当前矩阵,为什么?还是看下篇吧:

本文来源于ZwqXin http://www.zwqxin.com/ , 转载请注明
原文地址:http://www.zwqxin.com/archives/opengl/opengl-matrix-what.html


本篇文章承接上文:乱弹OpenGL中的矩阵变换(上) 。上篇中,我尝试从一种不太成熟的OpenGL世界观(注意,或许也是3D渲染世界的世界观)来认识这个OpenGL世界,向自己澄清了一些概念(尽管不够高清)。这里我想继续从矩阵数学的角度想一想:究竟模型位置怎么在世界中各个空间的坐标系统中“转换”?——ZwqXin
OpenGL中的坐标系是右手坐标系,矩阵按列优先存储。这很让人混乱,因为线代里接触的都是行优先存储,突然就这么column-major了.....最初还窃认为该不该从向量角度让头脑清晰,后来看别人文章说这跟向量没啥关系,完全是一种规范:如同右手坐标系,只是一种规范。好吧,列就列啦:
mt0     mt4     mt8     mt12
mt1     mt5     mt9     mt13
mt2     mt6     mt10   mt14
mt3     mt7     mt11   mt15
有点怪是不?当然啦,连C语言学2维数组时都是row-major的,OpenGL却是先一竖下来,再来下一竖(column-major)...(考虑一块内存,第一个格子存mt0,第二存mt1.....)这就是OpenGL矩阵存储方式。上篇提到,模型变换(Mode-Translation),视图变换(View-Translation)乃至投影变换,这些决定了各个空间之不同的"针对坐标系的变换",实质产生出来的是一个左乘矩阵,这些矩阵就是这样存储的。如果你看过任何一本3D图形学的入门书前两章,那你应该知道模型变换(在OpenGL中反映为glTranslate,glScale,glRotate)所使用的矩阵。譬如我这里先让苹果绕z轴逆转个角度Θ,再让它变成原大小的A倍,再右移10单位:(P.S.翻译成OpenGL世界的语言:在模型空间坐标系确定的位置基础上,让世界空间坐标系绕z轴顺转角度Θ,坍缩成原来一半大小,并左移10单位,注意是坍缩后1单位表示的长度跟之前的不一样了。)
 
A*cosΘ-sinΘ0  10 
sinΘA*cosΘ00
00A*1   0
0001
   X
*     y     =   M * P(point of Apple)
      z
      1
 其中M是变换矩阵,点P(x,y,z,1)是苹果的其中一个点的坐标(记得吗?这个坐标是在模型空间确定的并且不变),它是一个竖向量形式的点。为什么是竖向量呢,因为OpenGL矩阵的左乘:(4X4)*(4X1)=(4X1)嘛,这是线形代数知识,(A行数XA列数)*(B行数XB列数)中,只有A列数=B行数,这两个矩阵(向量)才可以相乘。那为什么要左乘?因为OpenGL(点)向量是列向量!哈哈,不是忽悠,这根本就是“规范问题”,譬如D3D就全采取相反的,不多说。最后,思考者应该已经把上面那个矩阵跟再上面那个“模板”对应起来了吧(OPENGL在内存中把相乘的结果——这16个数按mt0=A*cosΘ, mt1=sinΘ, mt2=0, mt3=0, mt4=-sinΘ, mt5=A*cosΘ, mt6=0......这样的竖的顺序存放)。再譬如我在之前的ShadowVolume Demo中就这样定义了一个4X4矩阵类,并这样定义了一个矩阵(就是上面的mt嘛)左乘某点向量的方法:
 
class CMatrix16

public:
    float mt[16];
 
   inline CVector4D operator*(CVector4D & vec4) { 
return CVector4D(mt[0] * vec4.x + mt[4] * vec4.y + mt[8] * vec4.z + mt[12] * vec4.w ,
     mt[1] * vec4.x + mt[5] * vec4.y + mt[9] * vec4.z + mt[13] * vec4.w ,
    mt[2] * vec4.x + mt[6] * vec4.y + mt[10]* vec4.z + mt[14] * vec4.w ,
     mt[3] * vec4.x + mt[7] * vec4.y + mt[11]* vec4.z + mt[15] * vec4.w );       
 
   };
 
};
class CMatrix16
{
public:
 float mt[16];

   inline CVector4D operator*(CVector4D & vec4) {
return CVector4D(mt[0] * vec4.x + mt[4] * vec4.y + mt[8] * vec4.z + mt[12] * vec4.w ,
  mt[1] * vec4.x + mt[5] * vec4.y + mt[9] * vec4.z + mt[13] * vec4.w ,
 mt[2] * vec4.x + mt[6] * vec4.y + mt[10]* vec4.z + mt[14] * vec4.w ,
  mt[3] * vec4.x + mt[7] * vec4.y + mt[11]* vec4.z + mt[15] * vec4.w );  

   };

};
然后,我们回头看之前那条式子,得出的结果是(A*cosΘ*x - sinΘ*y + 10,sinΘ*x + A*cosΘ*y,A*z,1),这是点P的新位置,注意,再说一次,是“位置”而不是“坐标”,点P坐标依然是(x,y,z,1)。(当然,你还可以用这样的概念来区分。)我姑且把结果记作(MP),所有点的结果构成了苹果在世界空间的位置。好了,看看代码:
 
glMatrixMode(GL_MODEL);
glTranslatef(10,0,0);
glScalef(A,A,A);
glRotatef(Θ, 0,0,1)
  
DrawApple() ;
glMatrixMode(GL_MODEL);
glTranslatef(10,0,0);
glScalef(A,A,A);
glRotatef(Θ, 0,0,1)
 
DrawApple() ;
请从下往上看。你问为什么顺序是倒着的呢?这跟上篇遗留下来的问题很相似。现在经过模型变换来到了世界空间,接下来是视图变换了。设当前相机得出的左乘矩阵为V,那么下一步,相似地,就是V*(MP)=(VMP)。上篇说过,OpenGL把模型变换和视图变换合并为“模型视图变换”,也就是说,OpenGL只生成一个左乘矩阵VM,上面的两步乘法,在OpenGL中其实一步到位:VM*P=(VMP)。我们来到了视图空间。真正代码在此:
 
gluLookat(eye,look,up);
 
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();  
 
glTranslatef(10,0,0); 
glScalef(A,A,A); 
glRotatef(Θ, 0,0,1) 
   
DrawApple() ;
gluLookat(eye,look,up);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); 

glTranslatef(10,0,0);
glScalef(A,A,A);
glRotatef(Θ, 0,0,1)
  
DrawApple() ;
接下来由视景体设置,视口设置,投影处理得出的左乘矩阵是J,那么相似地,我们继续左乘:J*(VMP)=(JVMP),来到屏幕空间——OpenGL世界的出口(之后的往窗口坐标系映射等等已经不算OpenGL的工作了)。
 
glViewport(0,0,width,height);//设置视口(视窗)大小
  
glMatrixMode(GL_PROJECTION));  
glLoadIdentity(); 
gluPerspective(fov,aspect,near,far);
 
gluLookat(eye,look,up); 
 
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity();   
 
glTranslatef(10,0,0);  
glScalef(A,A,A);  
glRotatef(Θ, 0,0,1)  
    
DrawApple() ;
glViewport(0,0,width,height);//设置视口(视窗)大小
 
glMatrixMode(GL_PROJECTION)); 
glLoadIdentity();
gluPerspective(fov,aspect,near,far);

gluLookat(eye,look,up);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();  

glTranslatef(10,0,0); 
glScalef(A,A,A); 
glRotatef(Θ, 0,0,1) 
   
DrawApple() ;
是不是回到了上篇的结尾呢?恩,我从矩阵意义上再梳理了一次流程。然后,可以回答为什么代码是倒过来写的了吧?——这说明你很清楚,代码是按顺序从上往下执行的。没错,OpenGL中执行这些代码也是从上往下执行的。所以你看看吧,这次要从上往下看:第1句:视窗设置,没什么,它只剔除,不直接产生矩阵(而且还得在下面投影变换处发挥作用);第2句:接下来要作投影变换啦;第3句:glLoadIdentity(),哈哈!这才是重点——无论眼前的是什么,它都能把它初始化成一个单位矩阵!而这里的这个单位矩阵,是一切的开端,它确实就是一个单位矩阵(I)了,后面第4句视景体的设置产生的投影变换矩阵(J)右乘它:J= I*J;接下来第5句相机设置,第6句表示模型视图变换的开始,第7句又一个glLoadIdentity(),继续右乘:J= I*J*I,这有什么用啊?呵呵,因为接下来“模型视图变换”产生的矩阵VM要继续右乘这个结果,直接让两个变换矩阵相乘可以是可以,那么如果没有投影变换呢?呵呵,这是有可能的,先不说平时我们渲染,就我们哪天突然要在模型空间搞事(譬如上次ShadowVolumeDemo那样“回光返照”),单单应用“模型视图变换”就关联不到最初那个glLoadIdentity()了。所以让一个glLoadIdentity()在作变换前出现是好的:VM = I*VM,实际上所有变换前加一个glLoadIdentity()是好习惯。
好吧,整理一下:假设把苹果旋转,放大,移动的相应变换矩阵是R,S,T,相机那个是L,那么这里就是 VM =L*T*S*R,也是倒过来的吧呵呵。按代码顺序的话右乘起来是这样的:(JVM)= I*J*I*VM =I *J*I*L*S*T,等式右边项是严格按照相应代码顺序来右乘的。为什么这里变右乘了?事实上我们说OpenGL的矩阵左乘规范,它跟代码顺序是两码事,矩阵左乘是从逻辑上来说的(也就是上篇和本篇我在开讲代码执行顺序前讲述的那些故事的逻辑,是属于OpenGL世界的逻辑),代码顺序是属于编译器的哦。好了,这个(JVM)就是要把处于模型空间的物体转移到屏幕上来——这时候它才和苹果的顶点相乘:(JVMP)=(JVM)*P,看好了,也是右乘,当然的了——结果是,苹果那么多顶点在一次渲染周期内只被“用”了一次!要知道,得出(JVM)结果的计算只有那么几个矩阵相乘运算,但是苹果N个顶点就有N个(JVM)*P的相乘运算哦!如果代码执行顺序相反你觉得会怎样?“几个N相乘”这么多次运算哦!
 
 
这里还有概念要澄清:
1.我说了,苹果也好,其他任何画出来的“东西”也好,它们坐标是在给出顶点坐标的时候就确定在模型空间的了,变换的是位置,也许说它们变换了还不对——因为真正被变换的是坐标系:你上面也看到了,苹果的坐标是最后右乘上去的,之前一直变换的是最初那个单位矩阵,单位矩阵的变换也代表了最初各空间重合的OpenGL世界的坐标系——上篇说过,它的变换是反着模型的(当然也反着单位矩阵),这里也不妨说,它受变换的阶段顺序都是反着模型的——而且它是按照编译器执行顺序变换出来的,是真正的,真实存在的变换:OpenGL中所有的变换,都是在变换坐标系。

2.说法问题,“坐标”和“位置”,一路看下来你也知道,我不把它们当一回事(不想再罗嗦了恩)。但是更通常的叫法(虽然容易引起歧义但说得广泛),是把“坐标”(固定于模型空间的那个,模型刚刚在世界出现时候的位置- -看,又罗嗦了)称为“局部坐标(Local-Coordinate)”,把世界空间里面那个“位置”叫“世界坐标(World-Coordinate)”,也有直接简称它为坐标的(这样的明显不是高手),因为它最能被感知,也许你在了解什么模型空间模型变换等等等等这些概念前,唯一认识的就是世界坐标——它就标识着3D渲染窗口里那个虚拟3D世界不是么?恩,所以说世界空间是OpenGL世界中近乎“正常”的空间,类比一下,如果把我们人类所生活的空间叫“世界空间”的话,小说中描绘的到处扭曲的异次元空间就叫“模型空间”呀“屏幕空间”呀之类的了(笑)。遗憾的是OpenGL不直接给我们提供这个空间中各物体的坐标系位置呢~不怕,我们还有逆矩阵!
3.等有缘的你来发挖啦!错误啦认识问题啦,随便提。这里是ZwqXin: www.zwqxin.com, 我的3D旅途记录簿。(纪念今天2009.2.5.BLOG上轨道啦。)
最后...还有glPushMatrix()和glPopMatrix()呢?相信大家用得很多,也知道用处:在它们之外的东西不受它们里面的那些模型变换代码影响。譬如下面这里,苹果跟上面一样也是做那些变换。可是橙呢?旋转和放大对它无影响,它只是受到移动了(OpenGL世界说法是,对应坐标系移动了)。
 
glMatrixMode(GL_MODELVIEW);  
glLoadIdentity();    
  
glTranslatef(10,0,0);  
 
glPushMatrix();
  glScalef(A,A,A);   
  glRotatef(Θ, 0,0,1);       
  DrawApple() ;
glPopMatrix();
 
DrawOrange() ;
glMatrixMode(GL_MODELVIEW); 
glLoadIdentity();   
 
glTranslatef(10,0,0); 

glPushMatrix();
  glScalef(A,A,A);  
  glRotatef(Θ, 0,0,1);      
  DrawApple() ;
glPopMatrix();

DrawOrange() ;
不知道我的讲解有没有人满意。我自己倒是满意了。哈哈。后面我还会有文章说说逆矩阵运算的问题和作用,并赞NEHE,有兴趣的不妨CLICK一CLICK:

本文来源于ZwqXin http://www.zwqxin.com/ , 转载请注明
原文地址:http://www.zwqxin.com/archives/opengl/opengl-matrix-what-2.html




 


 

posted on 2009-04-23 16:33 doing5552 阅读(2095) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理