一、窗口管理
GLUT用5个函数执行初始化窗口所需要到任务:
1、glutInit(int *argc,char** argv)对GLUT进行初始化,并处理所有命令行参数。glutInit()应该在调用任何其他GLUT函数之前被调用。
2、glutInitDisplayMode(unsigned int mode)指定使用RGBA还是颜色索引模式。还可以指定使用单缓冲还是双缓冲。最后,可以使用这个函数来表示希望窗口拥有相关联到深度、模板、多重采样和/或累积缓冲区。例如,如果需要一个双缓冲、RGBA颜色模式以及一个深度缓冲区到窗口,可以调用glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)。
3、glutInitWindowPosition(int x,int y)指定了窗口左上角到屏幕位置。
4、glutInitWindowSize(int width,int size)指定了窗口的大小(以像素为单位)。
5、int glutCreateWindow(char* string)创建了一个带有OpenGL渲染环境的窗口。这个函数为新窗口返回一个唯一到标识符。注意:在调用glutMainLoop()函数之前,这个窗口并没有被显示。
二、显示回调函数
glutDisplayFunc(void(*func)(void))是所看到到第一个也是最为重要的事件回调函数。每当GLUT确定一个窗口的内容需要重新显示时,通过glutDisplayFunc()所注册的那个回调函数就会被执行。因此,应该把重绘场景所需要的所有代码都放在这个显示回调函数里。
如果程序修改了窗口的内容,有时候必须调用glutPostRedisplay(),后者将提示glutMainLoop()在它的下一个时机调用已注册的显示回调函数。
三、运行程序
最后,必须被调用glutMainLoop()。所有已经创建的窗口将在此显示,对那些窗口到渲染也开始生效。事件处理开始启动,已注册到显示回调函数被触发。一旦进入循环,它就永远不会退出。
四、处理输入事件
可以使用下面这些函数注册回调函数,当指定的事件发生时,这些函数便会被调用:
glutReshapeFunc(void(*func)int w,int h))表示当窗口的大小发生改变时应该采取什么行动。
glutKeyboardFunc(void(*func)(unsigned char key,int x,int y))和glutMouseFunc(void(*func)(int button,int state,int x,int y))允许把键盘上的一个键或者鼠标上的一个按钮与一个函数相关联,当这个键或按钮被按下或释放时,这个函数就会被调用。
glutMotionFunc(void(*func)(int x,int y))注册了一个函数,当一个鼠标按钮被按下时移动鼠标时,这个函数就会被调用。
五、管理后台进程
可以在glutIdleFunc(void(*func)(void))函数中指定一个函数,如果不存在其他尚未处理到事件(例如,当事件循环处于空闲的时候),就执行这个函数。这个函数接受一个函数指针作为它的唯一参数。如果传递NULL(0),就相当于禁用这个函数。
六、绘制三维物体
GLUT包含了几个函数,用于绘制下面这些三维物体:
圆锥体 二十面体 茶壶
立方体 八面体 四面体
十二面体 球体 圆环面
void glutWireCube(GLdouble size);
void glutSolidCube(GLdouble size);
void glutWireSphere(GLdoublw radius,GLint slices,GLint stacks);
void glutSolidSphere(GLdouble radius,GLInt slices,GLint stacks);
七、清除窗口
在计算机中,保存图片的内存通常被计算机所绘制到前一幅图像所填满,因此在绘制新场景之前需要把它清除为某种背景颜色。如果是字处理程序,在绘制新文本之前把背景清除为白色。如果所绘的是在航天飞机上所看到的太空景象,那么在开始绘制恒星、行星以及外星人到飞船之前需要把背景清除为黑色。也有时候,背景并不需要清除。
清除窗口这种方式有几点优势。首先,特殊的清除窗口函数的效率可能远远高于普通的绘图函数。其次,就像在之前所看到到那样,OpenGL允许任意设置坐标系统、观察点和观察方向。这样一来,判断窗口清除矩形的大小和位置就可能非常困难。最后,在许多机器上,图形硬件除了包含被显示到像素颜色的缓冲区之外,还包含许多别的缓冲区。这些缓冲区随时可能被清除,如果有一条命令能够按照任意组合形式清除这些缓冲区,无疑是非常方便的。
例如,下面这两行代码把一个RGBA模式的窗口清除为黑色。
glCLearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
第一行代码把清除颜色设置为黑色,第二行代码把整个窗口清除为当前的清除颜色。glClear()的唯一参数表示需要被清除的缓冲区。在这个例子里,程序只清除颜色缓冲区,显示在屏幕上的图像仍然保持原样。例如,为了同时清除颜色缓冲区和深度缓冲区,只要使用下面这个操作序列就可以:
glClearColor(0.0,0.0,0.0,0.0);
glClearDepth(1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
在上面到代码里,glClearColor()函数的作用和前一段代码相同。glClearDepth()函数指定了深度缓冲区中的每个像素需要被设置的值。
void glClearColor(GLclampf red,GLclampf green,GLclampf blue,GLclampf alpha);
void glClear(GLbitfield mask);
用当前的缓冲区清除指定的缓冲区。mask参数的值如下:
缓冲区 名称
颜色缓冲区 GL_COLOR_BUFFER_BIT
深度缓冲区 GL_DEPTH_BUFFER_BIT
累积缓冲区 GL_ACCUM_BUFFER_BIT
模版缓冲区 GL_SIENCIL_BUFFER_BIT
八、强制完成绘图操作
glFlush()并不等待绘图完成,它只是强制绘图命令开始执行,因此保证所有的命令都在有限的时间内执行,即使在此之后并没有任何渲染命令需要执行。
九、坐标系统工具箱
无论是在刚打开窗口的时候,还是在以后移动窗口或改变窗口大小的时候,窗口系统都会发送一个事件来通知你。如果使用是GLUT,它会自动产生通知,并且在glutReshapeFunc()中注册的那个函数将会调用。必须注册一个回调函数,完成下列任务:
1、重新建立一个矩形区域,把它作为新的渲染画布
2、定义一个用于绘制物体的坐标系统
例如,可以调用glutReshapeFunc(reshape),其中reshape(int w,int h)。
void reshape(int w,int h)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLdouble) w,0.0,(GLdouble) h);
}
在系统内部,GLUT向这个函数传递两个参数:width和height,它们表示这个新的(或经过移动的、或改变了大小的)窗口的宽度和高度(以像素为单位)。glViewport()函数调整用于绘图的像素矩形,使它占据整个新窗口。接下来的3行代码调整用于绘图的坐标系统,使左下角到坐标为(0,0),右上角的坐标为(w,h)。gluOrtho2D函数的作用就是,指定这个2D平面的左,右,上,下的坐标,以指定整个坐标系,想要将OpenGL的坐标体系换成windows那样,只需要如下调用gluOrtho2D即可:
gluOrtho2D(0.0,(double)Width,(double)Height,0.0);
即,指定客户去左边界坐标为0,右边界坐标为客户区宽度,下边界坐标为客户区高度,上边界为0,这样,一个windows坐标体系就诞生了。在OpenGL中由于更惯用的是:
gluOrtho2D(0.0,(double)Width,0.0,(double)Height);
体系,这样于真实笛卡尔坐标体系第一象限一致,也与OpenGL中默认的x,y轴方向一致。
十、描述点、直线和多边形
用户可以把顶点指定为二维的形式(也就是只有x和y坐标),并由OpenGL为它赋一个值为零的z坐标。
OpenGL是根据三维投影几何的齐次坐标进行操作的。因此,对于内部的计算,所有的顶点都是用4个浮点坐标值(x,y,z,w)来表示的。如果w不等于0,那么这些坐标值就对应于欧几里德三维点(x/w,y/w,z/w)。可以用OpenGL函数指定w坐标,如果未指定w坐标,它就默认为1.0.
矩形
void glRect{sifd}(TYPE x1,TYPE y1,TYPE x2,TYPE y2);
void glRect{sifd}v(TYPE *v1,TYPE *v2);
绘制由角顶点(x1,y1)和(x2,y2)所定义的矩形。这个矩形位于z=0的平面上,并且它的边与x轴和y轴平行。
指定顶点
void glVertex{234}{sifd}[v](TYPE coords);
既可以为一个顶点提供多达4个的坐标(x,y,z,w)也可以只提供2个坐标(x,y)。如果使用的函数版本并没有显式指定z或w,z就会被当作0,w则默认为1.glVertext*()函数只有在位于glBegin()和glEnd()之间才有效。
几何绘图图元
void glBegin(GLenum mode);
标志着一个顶点数据列表的开始,这个顶点描述了一个几何图元。mode参数指定了图元的类型,如下:
几何图元的名称和含义
值 含义
GL_POINTS 单个的点
GL_LINES 一对顶点被解释为一条直线段
GL_LINE_STRIP 一系列的连接直线段
GL_LINE_LOOP 和上面相同,但第一个顶点和最后一个顶点彼此相连
GL_TRIANGLES 三个顶点被解释为一个三角形
GL_TRIANGLE_STRIP 三角形的连接串
GL_TRIANGLE_FAN 连接成扇形的三角形系列
GL_QUADS 四个顶点被解释为一个四边形
GL_QUAD_STRIP 四边形的连接串
GL_POLYGON 一个简单的凸多边形的边界
void glEnd(void);
标志一个顶点数据列表的结束。
十一、基本状态管理
为了打开或关闭某些状态,可以使用下面这两个简单的函数:
void glEnable(GLenum cap);
void glDisable(GLenum cap);
还可以查询一个状态当前是否处于打开还是关闭状态:
GLboolean glIsEnable(GLenum capability)
根据被查询的状态当前处于启用还是禁用状态,返回GL_TRUE或GL_FALSE。
可以使用5个查询函数,查询许多状态的当前值:
void glGetBooleanv(GLenum pname,GLboolean *params);
void glGetIntegerv(GLenum pname,GLint *params);
void glGetFloatv(GLenum pname,GLfloat *params);
void glGetDoublev(GLenum pname,GLdouble *params);
void glGetPointerv(GLenum pname,GLvoid **params);
params参数是个符号变量,表示需要返回的状态变量。params是一个指定类型的数组指针,指向包含返回数据的位置。
十一、显示点、直线和多边形
为了控制被渲染的点的大小,可以使用glPointSize()函数,并在参数中提供一个值,表示希望的点的大小(以像素为参数)。
void glPointSize(GLfloat size);
设置被渲染点的宽度,以像素为单位。size必须大于0.0,在默认情况下为1.0。
如果抗锯齿功能被禁用(默认情况),带小数的宽度值被四舍五入为整型值,在屏幕上绘制的是对齐的正方形像素区域。因此,如果宽度值为1.0,这个方块就是1个像素乘以1个像素,如果宽度为2.0,这个方块就是2个像素乘以2个像素。
如果启用了矿局吃或多重采样,屏幕上绘制的将是一个圆形的像素区域,位于边界的像素在一般情况下使用的颜色强度较小,使边缘具有更平滑的外观。在这种情况下宽度值并不会被四舍五入。
大多数OpenGL实现都支持非常大的点。可以使用glGetFloatv()函数(以GL_ALIASED_POINT_RANGE为参数)查询在未进行抗锯齿处理的情况下最小和最大的点。类似地,可以在这个函数中使用GL_SMOOTH_POINT_SIZE_RANGE为参数查询在进行了抗锯齿处理的情况下最小和最大的点。以GL_SMOOTH_POINT_SIZE_GRANULARITY为参数调用glGetFloatv()函数将返回系统对特定的抗锯齿点在大小方面的精度。例如,如果调用glPointSize(2.37),并且返回的粒度值为0.1,那么这个点的将四舍五入为2.4.
直线的宽度
void glLineWidth(GLfloat width);
以像素为单位设置宽度,用于直线的渲染,width参数必须大于0.0,在默认情况下为0.0.
如果为使用抗锯齿功能,那么宽度为1、2和3的直线将分别画成1、2和3个像素的宽度。如果启用了抗锯齿功能,它就允许使用非整数的宽度,位于边界处的像素一般会画得淡一点。可以使用GL_ALIASED_LINE_WIDTH_RANGE为参数查询受系统所支持的直线宽度的方位。为了查询系统所支持的抗锯齿直线的最小和最大宽度,以及使用的OpenGL实现所支持的直线宽度粒度,可以分别用GL_SMOOTH_LINE_WIDTH_RANGE和GL_SMOOTH_LINE_WIDTH_GRANULARITY为参数调用glGetFloatv()函数。
点画线
可以使用glLineStipple()函数定义点画模式,然后glEnable()函数启用直线点画功能。
glLineStipple(1,0x3F07);
glEnable(GL_LINE_STIPPLE);
void glLineStipple(GLint factor,GLushort pattern);
设置直线的当前点画模式。pattern参数是个由1和0组成的16位序列。从这个模式的低位开始,一个像素一个像素进行处理。如果模式中对应的位为1,就绘制这个像素,否则就不绘制。模式可以使用factor参数进行扩展,它与连续的1和0的子序列相承。因此,如果模式中出现了连续3个1,如果factor是2,那么它们就扩展为6个连续的1.必须以GL_LINE_STIPPLE为参数调用glEnable()才能启用直线点画功能。可以向glDisable()函数传递同一个参数,禁用直线点画功能。
多边形的细节
1.点、轮廓或实心形式的多边形
多边形具有两个面:正面和背面。取决于哪一面将面对观察着,它们可能会被渲染成不同的样子。
void glPolygonMode(GLenum face,GLenum mode);
控制一个多边形的正面和背面的绘图模式。face参数可以是GL_FRONT_AND_BACK、GL_FRONT或GL_BACK。mode参数可以是GL_POINT、GL_LINE或GL_FILL,表示多边形应该被画成点、轮廓还是填充形式。在默认情况下,多边形的正面和背面都被画成填充模式。
例如,可以通过下面这两个函数调用,把正面画成填充形式,把背面画成轮廓模式:
glPolygonMode(GL_FRONT,GL_FILL);
glPolygonMode(GL_BACK,GL_LINE);
2、反转和剔除多边形表面
void glFrontFace(GLenum mode);
控制多边形的正面是如何决定的。在默认情况下,mode是GL_CCW,它对应于窗口坐标上一个投影多边形的有序顶点的逆时针方向。如果mode是GL_CW,顶点顺序为顺时针方向的表面被认定是正面。