《OpenGL游戏程序设计》 K.霍金/D.阿斯特 著 田昱川 译
1. 绘制环境/设备环境
操作系统在使用OpenGL之前必须提供设置绘制窗口的功能
在windows中,图形设备接口用设备环境记录有关绘制模式和命令的设置
在OpenGL中,用绘制环境来记录OpenGL的设置和命令。
设备环境与绘制环境不同。
设备环境在GDI调用中被指定。
绘制环境在OpenGL调用中被指定。
在创建绘制环境之前必须设置设备环境的像素格式。
2. 像素格式
3. OpenGL中的变换
视图变换 设定视点的位置
模型变换 处理场景中物体的移动
投影变换 定义视体和裁剪平面
视区变换 将场景的2D投影映射到绘制窗口
视图模型变换 视图变换和模型变换的合并
4. 视点和眼坐标
对于OpenGL中的变换和观察,最重要的概念之一就是视点坐标系或者叫眼坐标系。在OpenGL中,默认的视点始终朝向z轴的负方向。
无论进行何种变换,眼坐标系始终保持不变
5. 视图变换
视图变换是最先应用于场景变换,用来定位和定向视点。
视点的默认方向是指向Z轴的负方向,位置位于原点(0,0,0)。
可以通过平移和旋转命令来改变视点的位置和指向,实际上就是进行视图变换操作。
视图变换必须在其他任何变换操作之前完成,这是因为这一变换相对于眼坐标系改变了当前的坐标系 ,其他任何变换操作都是基于这个修改过的当前坐标系来进行的。
进行视图变换:首先,必须清理当前矩阵。可以通过glLoadIdentity()函数完成。
void glLoadIdentity(void)
函数将当前矩阵设置为单位矩阵,步骤是必须的,因为绝大多数的变换命令都是操作当前矩阵并为其设置各自的值。没有此步骤,可能引起意想不到的结果。
初始化当前矩阵之后,可以用几种不同的方法来生成视图矩阵。
1:让视图矩阵等于单位矩阵,这样应用视点默认的位置和方向,位于原点,指向z轴的负方向
2:使用gluLookAt()函数指定一条延伸自视点的视线。此函数封装了一系列平移和旋转命令。
3:使用平移和旋转模型变换命令,即glTranslate*()和glRotate*()函数。此方法是相对于一个禁止的视点来移动3D世界中的物体。
4:定制自己的坐标系,使用平移和旋转变换创建自己的视点轨迹(例如:为视点绕某一个物体旋转的场景定制极坐标系)
6. 模型变换
模型变换运行通过平移、旋转、缩放来操作一个模型的位置和指向。可以一次执行一操作,也可以将所有操作合并成一个来一次执行。
7. 投影变换
投影变换用来定义视体和裁剪平面。通常在模型变换之后进行。可以认为投影变换决定了那些物体在视体内以及对其的观察方式
OpenGL支持两种类型的投影变换:透视投影/正交投影(平行投影)
8. 视区变换
此变换将透视投影变换生成的2D场景映射到窗口的绘制区。可以认为视图(应该是视区?)变换根据绘制区的尺寸决定了最终的图像应该是被放大还是应该被缩小。
OpenGL矩阵
1. 模型视图矩阵
模型视图矩阵定义了用于定位和定向物体的坐标系。是4*4矩阵
函数 void glMatrixMode(GLenum mode);指定要修改的矩阵是模型视图矩阵还是投影矩阵。
如果要修改模型视图矩阵 glMatrixMode(GL_MODELVIEW)
其他参数:
GL_PROJECTION 投影矩阵
GL_TEXTURE 纹理矩阵
大多数情况下,将模型视图矩阵设为当前矩阵之后,需要对其复位。调用glLoadIdentity()函数。会使矩阵复位为单位矩阵。并将当前坐标系复位到原点。
复位模型视图矩阵代码:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
2. 平移变换
平移允许在3D空间中将物体从一个位置移动到另一个位置。
函数:
void glTranslatef(GLfloat x, GLfloat y, GLfloat z);
void glTranslated(GLdouble x,GLdouble y, GLdouble z);
两个函数的不同在于参数的数据类型。一个是浮点型,一个是双精度。x,y,z分别指定了沿x,y,z轴的平移量。
例:glTranslatef(3.0f,1.0f,8.0f);
物体沿x轴正方向移动3个长度单位,沿Y轴正方向移动1个单位长度,沿z轴正方向移动8个单位长度。
3. 旋转变换
函数:
void glRotatef(GLfloat angle,GLfloat x,Glfloat y, GLfloat z);
void glRotated(GLdouble angle, GLdouble x,GLdouble y,GLdouble z);
glRotatef(135.0f,0.0f,1.0f,0.0f);绕Y轴逆时针旋转135度。
如果想要顺时针旋转,可以讲旋转角度指定为负数。
如果绕任意轴旋转:
需要用参数x,y,z定义任意轴矢量。要绕矢量(1,1,0)定义的轴旋转90度,这一旋转轴是从原点到(1,1,0)的线段。
glRotatef(90.0f,1.0f,1.0f,0.0f);
4. 缩放变换
缩放时:物体的顶点根据每个轴的缩放因子沿3个轴分别拉长或者压缩。
函数:
void glScalef(GLfloat x,GLfloat y,GLfloat z);
void glScaled(GLdouble x,GLdouble y,GLdouble z);
glScalef(2.0f,2.0f,2.0f);将一个物体的各个方向上的尺寸都放大两倍
glScalef(2.0f,1.0f,1.0f);将一个物体x轴方向放大两倍,其他轴不变
glScalef(0.5f,0.5f,0.5f);物体尺寸缩小为原来的一半
5. 矩阵堆栈
OpenGL中有3类矩阵堆栈
1. 模型视图矩阵堆栈
2. 投影矩阵堆栈
3. 纹理矩阵堆栈
模型视图矩阵实际上是模型视图矩阵堆栈的栈顶,投影矩阵也是投影矩阵堆栈的栈顶,纹理矩阵堆栈被用于坐标变换。
堆栈函数:
glPushMatrix()
glPopMatrix()
如果向堆栈中压入了过多的矩阵,OpenGL产生错误GL_STACK_OVERFLOW
如果堆栈中只有一个矩阵的情况下使用POP函数,产生错误GL_STACKUNDERFLOW
6. 自定义矩阵
载入自定义矩阵:将新的矩阵载入到矩阵堆栈中
void glLoadMatrixd(const GLdouble *matrix);
void glLoadMatrixf(const GLfloat *matrix);
矩阵是4*4,使用一个16个元素的一维数组,例如:
GLfloat identity[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,0.0,0.0,0.0,1.0};
不建议使用二维数字,因为C/C++中二维数字以行为主,OpenGL中以列为主,访问同一元素下标不一样。
矩阵的乘法:用新的矩阵与当前矩阵相乘。
void glMultMatrixd(const GLdouble *matrix);
void glMultMatrixf(const GLfloat *matrix);