OpenGL学习笔记-OpenGL的变换和矩阵

 

OpenGL的变换和矩阵

1)指定矩阵类型
OpenGL中使用glMatrixMode指定当前要设置的矩阵类型,常用的参数是GL_PROJECTION和GL_MODELVIEW,还有GL_TEXTURE。OpenGL将视点变换(即摄像机变换)和模型变换(即物体变换和世界变换)合二为一了。glMatrixMode指定的模式一但指定就不会变除非再次调用glMatrixMode,所以一般在reshpae里设定GL_PROJECTION之后再使用glMatrixMode指定当前矩阵类型为GL_MODELVIEW,那么以后设置的变换矩阵就都是模型视点矩阵。
2)模型视点矩阵设定顺序
在设定模型视点矩阵时,如果使用gluLookAt设定视点矩阵,必须先调用gluLookAt,然后再设定各个模型变换矩阵。而且由于每帧重新刷新,矩阵不会自动清除(矩阵设定都是右乘到栈顶),所以每帧一开始要使用glLoadIdentity将模型视点矩阵设成单位阵,然后用gluLookAt设定视点矩阵,然后是各模型变换矩阵。
3)变换矩阵设定和执行顺序
由于OpenGL使用的是向量右乘矩阵(向量是列向量,矩阵是列主矩阵),V'=M X V,而每次使用glTranslate*,glScale* ,glRotate*等的时候是将所指定的矩阵右乘到当前矩阵栈栈顶的矩阵上,比如原栈顶矩阵为I,使用glTranslate*指定矩阵T,那么当前变换矩阵就是IxT,如果再用glScale*指定一个缩放矩阵S,那么当前矩阵就是IxTxS,用来变换向量就变成 V' = IxTxSxV,效果就是先缩放再平移,可见指定矩阵的顺序是和矩阵变换向量的执行顺序相反的。如果这儿在代码中先调用glScale*,再调用glTranslate*,就会变成先平移再缩放,结果是很不一样的,因为缩放是针对中心点的坐标值变化,如果先平移,等于这些点离中心点远了,再放大就会更加偏离中心点。
示例代码:
 glPushMatrix();   
 glTranslatef(10.0f,0.0f,0.0f);
 glScalef(2.0f,2.0f,2.0f);
 glutWireCube(1.0); 
 glPopMatrix(); 
 
 glPushMatrix();  
 glScalef(2.0f,2.0f,2.0f);
 glTranslatef(10.0f,0.0f,0.0f); 
 glutWireCube(1.0); 
 glPopMatrix();

同样对于视点变换和模型变换,由于是先指定视点变换(调用gluLookAt)后指定模型变换,所以实际效果是先模型变换再视点变换,这与一般图形学上的流水线顺序一致。

4)glLoadIdentity,glPushMatrix/glPopMatrix的使用
在使用glMatrixMode(GL_PROJECTION)后要立刻调用glLoadIdentity,glMatrixMode本身不会将栈顶矩阵清成单位阵。在每帧开始要调用glLoadIdentity将模型视点矩阵设成单位阵(否则会累积上一帧矩阵变换的最终效果)。在设定模型变换矩阵时,也可以使用glLoadIdentity,这会清除之前所有变换矩阵的累积效果重新开始矩阵设定,当然最方便的还是glPushMatrix/glPopMatrix组合,首先他的效率比glLoadIdentity高,执行glPushMatrix时复制当前的矩阵并入栈(新矩阵位于栈顶,原矩阵被压入栈中),这样之后所做的变换就可以累积原来的变换效果,之后调用glPopMatrix会将原变换矩阵弹出,这样就恢复了原来的变换矩阵,不受push/pop之间矩阵变换的影响。这种矩阵栈的结构特别适合层次关系,一般至少支持32层。(投影矩阵支持2层,但一般没用)

5)模型变换矩阵函数
即glTranslate*,glScale* ,glRotate*,使用这些函数速度比自己设置矩阵并调用glMultMatrix*快。
使用glScale*会对光照产生影响,必须再次归一化法线。(因为OpenGL会将模型变换应用到法线上)
连续旋转时应该是记录旋转角度并以之调用glRotate*,因为多次进行微小旋转会导致误差

6)视点变换矩阵
可以用gluLookAt指定,也可以自己封装函数实现功能

7)投影变换
投影矩阵一般是在reshape(屏幕尺寸设定或变化的时候)里调用,必须首先调用:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
投影变换定义视景体,OpenGL会根据视景体进行裁剪(应该是会生成一个齐次空间透视裁剪矩阵并进行裁剪)
使用glFrustum指定透视投影的视景体,他会生成一个透视矩阵并将其与当前矩阵相乘
也可以使用gluPerspective指定,注意他使用的是fovy和w/h
还可以自己封装类似函数(要使用glMultMatrix*)

8)视口变换,深度坐标
glViewport指定视口
glDepthRange设定深度值范围,默认为0.0~1.0(书中说这是在视口变换过程对z坐标编码的方式。这应该是OpenGL设定的齐次透视裁剪空间的z值范围吧)

你可能感兴趣的:(OpenGL学习笔记-OpenGL的变换和矩阵)