2,ClientHeight div 2,1,100);
glMatrixMode(GL_MODELVIEW); );//将矩阵变换对象切换为模型视图变换。
在上面的代码中,你看到了一个陌生的函数:glMatrixMode。它的作用是告诉OpenGL接下来我们将要设置投影变换矩阵。 1.2.2 创建透视投影
透视投影对远处的物体根据距离进行缩短或压缩变换。这使得远处的物体看起来小些,从而更加真实。因为远处的景物更小,所以随着距离的增加,观察者应该能看到更多的景物。因此,透视投影的可视区域应是一个被称为平截头体的几何形状。如图3.1-6所示。
图3.1-6 透视投影
和平行投影相似,只要把函数glOrtho的调用改为glFustum或者gluPerspective。
gluPerspective(fovy, aspect, zNear, zFar: GLdouble);
其中,fovy为垂直方向上可见区域的角度(即上修剪平面和下修剪平面的二面角);
aspect为高度与宽度的纵横比(即 Width/Height 的比值); zNear和zFar为近、远修剪平面。
由gluPerspective定义的平截头体
我们用下面的代码定义透视投影: glMatrixMode(GL_PROJECTION);
gluPerspective(60,ClientWidth/ClientHeight,1,zFar); glMatrixMode(GL_MODELVIEW);
其中,zFar根据要绘制场景的大小设置不同的值。 1.3 设置背景颜色
这一步是可选的。我们可以调用glClearColor函数来设置用于清空屏幕和缓冲区的颜色。
glClearColor(R,G,B,A:GLFloat);
其中,R,G,B,A分别表示颜色的R、G、B分值和透明度值。取值范围均为0-1之间。例如,下面的代码把背景色设置为黑色: glClearColor(0,0,0,1);
1.4 绘制之前,清空屏幕和缓冲区
一般地,我们把所有绘制函数的调用写在RenderScene过程中。在每次绘制之前,我们都应该清空屏幕和缓冲区。下面的代码用指定的清空颜色清空它们: void RenderScene {
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); ...图形绘制... }
2 使用OpenGL绘制基本图元
一切复杂的东西都是由简单而基本的元素构成的。在OpenGL中,组成复杂图形的基本元素被成为图元。掌握了基本图元的绘制方法,就能绘制出任何复杂的物体。
GlBegin( GL 枚举模型) 参数:
GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_QUADS, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUAD_STRIP,GL_POLYGON
在glBegin和glEnd之间可以使用的部分函数:
glVertex, glColor, glIndex, glNormal, glTexCoord, glEvalCoord, glEvalPoint, glMaterial, and glEdgeFlag
OpenGL为我们提供了以下几种图元: 点 线
连续线 封闭线 三角形 三角条形 三角扇形 四边形 多边形
2.1 绘制三角形
在调用glVertex之前和之后,我们需要调用glBegin和glEnd这两个函数来标识图元的开始和结束。
在调用glBegin函数时,我们需要传入一个参数,以告诉OpenGL我们将绘制什么类型的图元。传入GL_TRIANGLES表明我们将要绘制三角形。例如: glBegin(GL_TRIANGLES); glVertex(1,0,1); glVertex(0,1,0); glVertex(1,1,0); glEnd;
将绘制一个以点(1,0,1)、(0,1,0)、(1,1,0)为顶点的三角形。 2.2 绘制三角条形
和绘制三角形相同,只要把glBegin的参数该为GL_TRIANGLE_STRIP即可。例如:
glBegin(GL_TRIANGLE_STRIP); glVertex(1,0,1); glVertex(0,1,0); glVertex(1,1,0); glVertex(1,3,0); glVertex(4,8,2); glEnd;
2.3 绘制三角扇形
和绘制三角形相同,只要把glBegin的参数该为GL_TRIANGLE_FAN即可。由于绘制方法大致相同,这里不再举例了。 2.4 绘制点、线、连续线、封闭线
下面列举了绘制这些图元应传给glBegin的值。 点:GL_POINTS 线:GL_LINES
连续线:GL_LINE_STRIP 封闭线:GL_LINE_LOOP
值得说明的是图元GL_LINE_STRIP和GL_LINE_LOOP。
GL_LINE_STRIP和GL_TRIANGLE_STRIP原理是一样的。也就是从第2个顶点开始,第n个顶点与第n-1个顶点构成一条直线。例如: glBegin(GL_LINE_STRIP); glVertex(A.x,A.y,A.z); glVertex(B.x,B.y,B.z); glVertex(C.x,C.y,C.z); glEnd;
将绘制出两条线段:线段AB和线段BC。
图元GL_LINE_LOOP建立在GL_LINE_STRIP的基础之上。与GL_LINE_STRIP不同的是,GL_LINE_LOOP会在最后一个顶点和第一个顶点之间再连一根直线,构成一个封闭图形。如果把上述代码的GL_LINE_STRIP参数该为GL_LINE_LOOP,那么将绘制出三条线段:线段AB、BC和CA。 2.5 绘制四边形和多边形
四边形(QUAD)也属于使用几率较高的图元。只要把glBegin的参数改为GL_QUADS,就可以绘制四边形。把参数改为GL_POLYGON,则可以绘制一个多边形。
然而,仔细观察你将发现,无论是四边形还是多边形,只要花一点工夫,他们都可以使用三角形来表示。而且,由于现在的显卡都对三角形的绘制做了大量的优化,使得绘制三角形的速度比绘制多边形的速度快得多。因此请尽量不要使用多边形这种图元以提高渲染速度。
如果你要使用四边形或多边形,请注意以下几点: 1.使用OpenGL绘制的多边形,必须是凸多边形;
2.绘制的多边形的所有顶点都必须处在同一个平面上。
由于这些限制,使得绘制多边形这种图元显得不怎么方便。这也突出了使用三角形的优点——你永远也不用担心绘制出来的三角形是无效的。你可以尽情地使用三角形绘制各种复杂多边形。 3 使用深度测试 我们知道,当一个平面或物体挡住了另一个物体时,后面的物体是不可见的。此时,我们应该避免绘制后面的物体。这个时候,我们可以使用OpenGL的一个功能:深度测试(Depth Test,也称深度缓冲(z-Buffer))来剔除这些被挡住的表面。深度测试就是在绘制像素时,计算该像素所代表的物体离观察者的距离,称为z值。如果该值在同一个像素上所有的z值中是最小的,就绘制该像素,否则就跳过。这是一个解决深度问题的有效方法。我们只需要调用函数 glEnable(GL_DEPTH_TEST); 就可以开启深度测试。调用 glDisable(GL_DEPTH_TEST); 关闭深度测试。 4 背面剔除
如果你将要绘制一些实心的物体,那么这个实心物体内部的表面将永远是不可见的。而OpenGL并不知道这些面不可见,它会照样对他们进行计算和绘制。虽然最后还是没有将这些背面绘制在屏幕上,但是浪费了许多不必要的时间。因此,我们应该开启背面隐藏功能剔除这些不可见的表面。 绕法
如果我们把一个物体朝着外面的表面都按照逆时针的顺序传给OpenGL,那么OpenGL就会认为这个面是朝外面的。这个时候,我们开启背面剔除就不会有什么影响。但如果你没有遵守这个规定就开启了背面剔除,将得不到正确的渲染结果。我们可以通过函数glFrontFace的调用来改变这一规则。例如: glFrontFace(GL_CCW);
将让OpenGL认为所有逆时针缠绕的表面是正面,如果把 GL_CCW 改为 GL_CW ,那么OpenGL将认为所有逆时针缠绕的面是正面。 开启表面剔除
在渲染之前,添加下面的代码来打开表面剔除:
glCullFace(GL_BACK);//隐藏背面,如果把参数改为GL_FRONT则隐藏正面。 glEnable(GL_CULL_FACE); 关闭表面剔除
有些物体,无论是正面还是背面都有可能是可见的(比如一张纸,既有正面又有背面),在渲染这些物体的时候,我们应该关闭表面剔除。只需添加以下代码: glDisable(GL_CULL_FACE); 5 将渲染结果显示到屏幕上
在所有物体绘制完成之后,我们要调用函数SwapBuffers来显示渲染结果:
转:OpenGL基本概念入门3——矩阵变换 2009-05-04 18:36 1 平移
glTranslatef(x,y,z); 其中,x,y,z分别表示在X、Y、Z轴上平移的量 2 旋转
与平移类似,OpenGL也为我们提供了一个高级函数用于旋转物体: glRotatef(Angle,x,y,z);
这个函数将生成并应用一个将坐标系以向量(x,y,z)为轴,旋转angle个角度的矩阵。 3 缩放
缩放变换其实是将坐标系的x、y、z轴按不同的缩放因子展宽,从而实现缩放效果。函数
glScalef(x,y,z);
把坐标系的X、Y、Z轴分别缩放x、y、z倍。 4 变换的叠加性质 使用变换时,我们应该注意的是,变换是叠加在上次变换的基础上的。也就是说,变换的效果会累积。每次调用变换函数时,会生成一个新的函数来乘以当前的模型视图矩阵,随后,新的矩阵将成为当前的模型变换矩阵,在下次执行变换时,会被新的矩阵相乘,因此作用效果将不断累积。
我们可以调用glLoadIdentity();函数将当前模型视图变换矩阵重置到初始状态,再进行新的绘制。如: void RenderScene() {
glMatrixMode(GL_MODELVIEW); //沿Y轴向上平移10个单位 glTranslatef(0,10,0); //画第一个球体 DrawSphere(5); //加载单位矩阵
glLoadIdentity();
//沿X轴向上平移10个单位 glTranslatef(10,0,0); //画第二个球体 DrawSphere(5); }
5 矩阵堆栈
如果每次变换前都把当前矩阵恢复到单位矩阵,也比较麻烦。更多时候,我们希望保存当前矩阵,执行一些变换之后,把当前矩阵恢复到上次保存时的状态。 OpenGL为我们提供了一个“矩阵堆栈”满足我们的这种要求。我们可以把当前矩阵压入堆栈中,然后执行一些变换,再弹出刚才压入的矩阵,从而把当前矩阵恢复到上次变换之前的状态。我们调用 glPushMatrix();
把当前矩阵压入矩阵堆栈,调用 glPopMatrix();