openGL初学函数解释汇总

openGL初学函数解释汇总

1.GLUT工具包提供的函数

//GLUT工具包所提供的函数
    glutInit(&argc, argv);//对GLUT进行初始化,这个函数必须在其它的GLUT使用之前调用一次。
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);//初始化显示模式,(颜色使用RGB,单缓冲GLUT_SINGLEGLUT_DOUBLE双缓冲)
glutSwapBuffers();//交换缓冲区 glutInitWindowPosition(100, 100);//初始化窗口位置 glutInitWindowSize(400, 400);//初始化窗口大小 glutCreateWindow("OpenGL程序窗口");//创建窗口 glutDisplayFunc(&myDisplay);//作图时一定要调用的函数 glutIdleFunc(&myIdle);//只要CPU空闲就可以运行该参数当中的函数 glutMainLoop();//进行一个消息循环,显示图像,窗口关闭则返回

2.OpenGL的标准函数

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清空颜色缓存以及深度缓存
glRectf(-0.5f, -0.5f, 0.5f, 0.5f);//画一个矩形。四个参数分别表示了位于对角线上的两个点的横、纵坐标
glFlush();//保证前面的OpenGL命令立即执行(而不是让它们在缓冲区中等待)。其作用跟fflush(stdout)类似


顶点的使用
glVertex3f(1.0f, 3.0f, 0.0f);//其中前缀glVertex不变,后面的3代表点的维度,f是浮点型(也可为i,d等等)
glBegin(GL_POINTS);//指定顶点的命令必须包含在glBegin函数之后,glEnd函数之前(否则指定的顶点将被忽略),括号中的参数指的是利用顶点需要的绘制的图像的类型,下面会有几种参数的介绍
......//输入顶点,要按一定顺序输入(程序会按顺序处理输入的顶点,glbegin()中的参数会告诉我们如何处理顶点)
glEnd();
//glBegin()当中的几种参数类型的介绍
GL_POINTS:按顺序在图中画出顶点
GL_LINES:将输入的顶点两两组合,绘制成线段
GL_TRIANGLE_FAN:输入的第一个点作为中心点,其余的点,按输入顺序,每两个点就可以和中心点组合成为一个三角形
GL_POLYGON,GL_LINE_LOOP:输入顶点绘制成凸多边形


顶点,直线,多边形的修整函数
//关于定点
glPointSize(5.0f);//定义顶点的大小
//关于直线
glLineWidth(5.0f);//定义直线的宽度
glEnable(GL_LINE_STIPPLE);//启用虚线模式,glDisable(GL_LINE_STIPPLE)可以关闭之
glLineStipple(1, 0x5555);//前一个参数是连续线段最大长度,后一个参数的二进制是16位,每一位如果是1那么画出点,否则不画
//关于多边形
//(1)多边形两面的绘制方式
glPolygonMode(GL_FRONT,GL_FILL);//凸多边形模式(正面or反面,填充方式[绘制边界或填充图案等等])
glPolygonMode(GL_BACK, GL_LINE);//同上介绍
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 同上介绍,设置两面均为顶点绘制方式
//(2)多边形正反面的概念
glFrontFace(GL_CCW);//定义凸包点列逆时针分布的面为正面,其中参数GL_CCW即为逆时针旋转,改为GL_CW则效果相反
//(3)剔除多边形表面
glEnable(GL_CULL_FACE);//来启动剔除功能(使用glDisable(GL_CULL_FACE)可以关闭之)
glCullFace(GL_BACK);//剔除多边形的反面,参数还可以是:GL_FRONT,GL_FRONT_AND_BACK
//(4)镂空的多边形,类似虚直线,多边形也可以镂空
glEnable(GL_POLYGON_STIPPLE);//来启动镂空模式(使用glDisable(GL_POLYGON_STIPPLE)可以关闭之)
glPolygonStipple(Mask);//其中Mask数组定义为static GLubyte Mask[128];自定义一幅图画,如何调取出图画的Mask数组?以下为调用方法
/////////////////////////////////////////////
static GLubyte Mask[128];
FILE *fp;
fp = fopen("mask.bmp", "rb");//打开保存的bmp文件
if( !fp )
exit(0);
if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )//移动文件指针,使得再读sizeof(Mask)个字节就会到达文件末尾
exit(0);
if( !fread(Mask, sizeof(Mask), 1, fp) )//读取文件sizeof(Mask)个字节到Mask数组中
exit(0);
fclose(fp);
glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple(Mask);
glRectf(-0.5f, -0.5f, 0.0f, 0.0f);   // 在左下方绘制一个有镂空效果的正方形
/////////////////////////////////////////////
glutSolidSphere(r,20,20);//参数r代表球体的半径,后两个参数代表绘制球体的精确程度,数值越大,绘制越精确

颜色的使用
glColor3f(0.0f, 1.0f, 1.0f);//前缀glColor不变,后缀3f代表有3个浮点型参数作为点的三维坐标
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);//定义“空”的颜色类型(也可以认为是最初的背景色)
glShadeModel(GL_SMOOTH);    // 点与点连成直线时,若两个顶点颜色不一,openGL默认会以渐变的颜色填充这条线段,修改该设定可采用这个函数,当前方式为平滑方式,这也是默认方式
glShadeModel(GL_FLAT);      // 介绍同上,单色方式,即以线段某一端的端点的颜色作为线段的颜色

模型变换和视图变换
glMatrixMode(GL_MODELVIEW);//设置当前操作的矩阵为“模型视图矩阵”,及可以利用矩阵进行旋转等变换
glLoadIdentity();//将当前矩阵设置为单位矩阵(还未进行任何旋转操作)
glRotatef(30.0, 0.0f, 0.0f, -1.0f);//glRotate前缀不变,后缀f代表参数是浮点型,第一个参数是旋转角度,后三个参数代表按照向量n=(0,0,-1)为轴进行旋转
glTranslatef(1.0f, 2.0f, 3.0f);//函数形式和旋转函数类似,3个参数的含义分别是沿着X,Y,Z轴正方向平移的距离
glScalef(1.0f,2.0f,3.0f);//函数形式同上,3个参数的含义:调用该函数以后,所有函数点的X,Y,Z坐标会乘上3个参数当中相应位置的参数数值,譬如参数为(1,2,3),则(x,y,z)变换后为(x,2y,3z)
gluLookAt(0, -20, 20, 0, 0, 0, 0, 0, 1);//(前三个参数为观察点位置坐标,中间三个参数为观察目标的位置坐标,后三个参数为观察者认为的上方的方向向量)
投影变换
投影变换就是定义一个可视空间,可视空间以外的物体不会被绘制到屏幕上,OpenGL支持两种类型的投影变换,即透视投影和正投影。
以下为投影函数
glMatrixMode(GL_PROJECTION);//投影也是使用矩阵来实现的。如果需要操作投影矩阵,需要以GL_PROJECTION为参数调用glMatrixMode函数
glLoadIdentity();//同模型和视图变换,在进行变换前要将矩阵设置为单位矩阵
//将可视空间设置为透视投影空间的函数:
glFrustum (left, right, bottom, top, near, far);//(left,bottom),(right,top)是被投影的裁剪平面左下角和右上角点的坐标,near是被投影的裁剪平面到视点(即观察点)的距离,far是通过投影产生的平面到视点的距离,near,far参数必须为正值
gluPerspective(fovy,aspect,Near,Far);//参数fovy为视角的大小(可以理解为视野的大小,视角越大,说明眼睛睁开的角度越大,视野就越开广,能看到东西越多,但是看到的物体会比较小,不清晰,视角越小,说明正眯着眼,只能看到局部的视野,但是看到的东西更清晰,如同放大镜的效果),aspect为实际窗口的宽高比,参数near,far含义同函数
glFrustum
以下为正投影函数
glOrtho(left, right, bottom, top, near, far);//
参数含义同glFrustum,作用是平行投影(即物体不会因为屏幕的远近而改变大小),可以当作是一个裁剪函数,从原图当中抠出一部分来作为原图的裁剪面。
视口变换
//视口变换,可以把上面透视、正投影处理后的投影面输出到显示器的窗口上指定的位置
glViewport(0, 0, (GLsizei)width, (GLsizei)height);//将裁剪窗口输出到屏幕,宽为width,高为height,注意如果裁剪面的长宽比例和输出比例(即width/height)不一样的话,输出时图像会被拉伸或收缩,要让裁剪面输出到屏幕后图形比例和原来一样的话,需要让裁剪面的长宽比和输出比例一致。
变换矩阵的存储及恢复功能
操作矩阵的堆栈,需要注意:模型视图变换和投影变换两者都有相应的堆栈,使用glMatrixMode来转换这两种变换类型
glPushMatrix();//把当前变换矩阵压入到堆栈
glPoatrix();//从堆栈中pop出一个矩阵,即恢复上一次存储的变换矩阵
glEnable(GL_DEPTH_TEST);//启用深度测试,防止后绘制的物体遮住先绘制的物体

双缓冲技术
在glutInitDisplayMode这个工具包函数里面启动双缓冲功能(可以理解为其中一个缓冲用于给计算机画图像,还有一个缓冲用于显示图像,当计算机画完,交换指着对应缓冲的指针,就实现了两个缓冲的交换,此时屏幕就显示计算机刚画完的图像了。)
glutSwapBuffers();//参考glut工具包函数
glutIdleFunc(&myIdle);//参考glut工具包函数
关于垂直同步的简单介绍(一个简单的例子)
设显示器的刷新频率为60HZ,意义为1秒钟刷新60次屏幕,现在电脑如果需要绘制图像,绘制一张的时间为1/50s,那么如果没有设置垂直同步,那么FPS(帧数)就是50了,1s显示50张画面。若设置了垂直同步,即每次刷新最多显示一张图片,那么显示器第一次刷新的时候(也就是1/60时),电脑还没有将图像绘制好,那么只能等到第二次刷新的时候才能输出一张图片,帧数就变成了30.可以看到帧数急剧下降了,如果计算机性能太好,1秒能画上百上千的图,这样显示器根本没法全部输出画好的图像,垂直同步也可以很好的防止资源过度浪费。

光照的基本处理
openGL把光照分解为光源、材质、光照模式三个部分,根据这三部分信息,以及物体表面的法线向量,可以确定最终的光照效果,接下来对每一部分函数逐一介绍
1:法线向量
glNormal*();//
2:控制光源
。。。
未完待续

 
显示列表 
在编写OpenGL程序时,遇到重复的工作,可以创建一个显示列表,把重复的工作装入其中,并在需要的地方调用这个显示列表
使用显示列表一般有四个步骤:分配显示列表编号、创建显示列表、调用显示列表、销毁显示列表
1:分配显示列表
glGenLists(x);//自动分配x个没有使用的并且连续的显示列表编号,譬如x=3,函数返回20,则分配到的显示列表编号为20,21,22
glIsList(x);//判断编号为x的显示列表是否存在
2:创建显示列表
glNewList(list, GL_COMPILE);//开始装入编号为list的显示列表,第二个参数GL_COMPILE表示内容只是装入显示列表,但暂时不执行,如果需要马上执行,参数改为GL_COMPILE_AND_EXECUTE
glEndList();//结束显示列表的装入
3:调用显示列表
glCallList(10);//调用编号为10的显示列表
glCallLists(4,GL_UNSIGNED_INT,lists);//第一个参数表示调用的列表的数量,第二个参数表示列表编号的存储格式,第三个参数表示编号所在地的指针
glListBase(k);//表示一个偏移量,偏移k个位置
//////////////////////
举个小例子
GLuint lists[] = {1, 3, 4, 8};
glListBase(10);
glCallLists(4, GL_UNSIGNED_INT, lists);
最终调用编号为11,13,14,18的显示列表
//////////////////////
4:销毁列表
glDeleteLists(10,4);//最终销毁编号为10,11,12,13的四个列表

混合
glEnable(GL_BLEND);//使用opengl混合功能,相应的,关闭该功能即为glDisable(GL_BLEND);
源颜色和目标颜色:源颜色即为当前需要画上去的颜色,目标颜色是原本存在于画板的颜色,采用RGBA,源颜色和目标颜色均有四个分量:(红色,绿色,蓝色,alpha值(亮度))
源因子和目标因子:源因子和目标因子是对应于源颜色和目标颜色的4维向量,即源颜色和目标颜色最后混合产生的颜色值为----(源因子·源颜色+目标因子
·目标颜色),其中·为向量作点乘
glBlendFunc(GL_ONE, GL_ZERO);//源因子和目标因子可以通过该函数进行设置,,函数前一个参数设置源因子,后一个参数设置目标因子。当中参数有好几种类型,以下分别进行介绍:
GL_ZERO:     // 表示使用0.0作为因子,实际上相当于不使用这种颜色参与混合运算。
GL_ONE:      // 表示使用1.0作为因子,实际上相当于完全的使用了这种颜色参与混合运算。
GL_SRC_ALPHA://表示使用源颜色的alpha值来作为因子。
GL_DST_ALPHA://表示使用目标颜色的alpha值来作为因子。
GL_ONE_MINUS_SRC_ALPHA://表示用1.0减去源颜色的alpha值来作为因子。
GL_ONE_MINUS_DST_ALPHA://表示用1.0减去目标颜色的alpha值来作为因子。
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//比较常用,相当于源颜色乘上它的alpha值,目标颜色乘上(1-源颜色alpha),这样源颜色alpha越大,源颜色混合占比越大。、
三维混合
三维混合要注意深度缓冲,深度缓冲记录了每一个像素点距离观察点又多近,如果将要绘制的像素比原来的像素更近,像素会被绘制,否则就会被忽略掉。所以一旦我们在近处绘制了半透明的图形,在缓冲区留下了信息,远处的图形将无法再绘制出来。这时可以这样解决问题:先绘制不透明的物体,因为不透明谁先谁后都不影响。之后将深度缓冲区设置为可读不可写,再接着画半透明的物体即可。绘制完毕后将深度缓冲区设置为可读可写。
glDepthMask(GL_FALSE);//将深度缓存区设置为只读形式。glDepthMask(GL_TRUE);将深度缓存区设置为可读可写形式

 BMP文件格式
BMP是像素文件,可以保存单色位图,16色或256色索引模式像素图,24位真彩色图。以上每种格式每一个像素的大小是1、4、8、24位,也就分别是18、12、1、3字节,BMP格式的文件在开始处有一个大小为54字节的文件头,文件头中包含了文件格式标识、颜色数、图象大小、压缩方式等信息,其中图像大小的信息比较有用,图像的高度和宽度都是32位的整数在文件中的地址是0x0012、0x0016d.
以下做法可以提取BMP格式文件的信息:
GLint width,height;
File *file;
fseek(file,0x0012,SEEK_SET);
fread(&width,sizeof(width),1,file);
//fseek(file,0x0016,SEEK_SET);可以省略这一步,因为提取完width指针已经转移到0x0012的4个字节之后了,也就是转到了0x0016
fread(&height,sizeof(height),1,file);
需要注意的一些地方:1:opengl通常使用RGB表示颜色,但BMP采用BGR,也就是反过来了。2:BMP文件格式采用“对齐”的机制,也就是每一行的所使用的位数一定要是4的整数倍,若不是,要一直补到4的整数倍才可以,所以不能简单的使用图像的高度乘上图片的宽度再乘上每一个像素的位数作为文件总的像素个数,要注意。
opengl的像素操作
glReadPixels(0,0,width,height,GL_BGR_EXT,GL_UNSIGNED_BYTE,pixelData);//该函数可以把显存中已经绘制好的图像信息保存在最后一个参数(是1个指针)所指的地方。该函数一共7个参数,其两个参数是选取图像的左下角顶点坐标(窗口最左下角为(0,0)),width,height是选取的区域的宽和高(像素数量),第五个参数表示读取像素的数据内容,譬如设置参数是GL_RED,则只读取图像的红色数据。因为bmp格式文件采用BGR,所以读取时可以采用GL_BGR_EXT,若使用GL_RBG参数来读数据,还要手动将每个像素的第一个字节和第三个字节交换。第6个参数读取的数据内容保存到内存时采用的存储格式,例如GL_UNSIGNED_BYTE可以把数据保存为GLubyte。第7个参数则是指针,这些数据会保存到指针指向的地点。
int alignment = 4;
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);//若要将图像数据保存在BMP格式文件中,那么在采用glReadPixels函数保存图像数据前,要使用glPixelStorei函数将需要保存的图像的每一行像素数据的字节补齐为4的倍数。其中第一个参数GL_UNPACK_ALIGNMENT表示“设置像素的对齐值”,第二个参数为具体按多少字节的整数倍对其。可以是1,2,4,8等等,即分别按照1,2,4,8字节的整数倍对其。
glDrawPixels(width,height,GL_BGR_EXT,GL_UNSIGNED_BYTE,pixelData);//该函数用于将保存在内存中的图像数据绘制出来。第一、二个参数为图像数据的高度和宽度(像素数量),第三个参数是读取像素的格式信息,第4个参数是图像存储在内存中的存储格式,最后一个是指针,指向内存中保存的图像信息的数据位置。
glRasterPosf();//注意glDrawPixels函数没有指定绘制位置,绘制位置可以由该函数设置。通过指定一个二维/三维/四维坐标,OpenGL将自动计算出该坐标对应的屏幕位置,并把该位置作为绘制像素的起始位置。
glPixelZoom(0.5f, 0.8f);//在绘制像素前,可以对对图像进行一些处理,譬如用该函数进行放大缩小,当设置参数为(0.5f,0.8f)则图像水平方向变为原来的50%,垂直方向变为原来的80%,默认从左下角开始往右上方绘制,若参数为负数,则绘制方向相反
glCopyPixels(0,0,width,height,GL_COLOR);//复制像素并进行绘制的操作,前两个参数代表被复制的图的左下角坐标,width,height是复制原来矩形的宽度和高度。最后一个参数代表复制原本像素的颜色。

纹理操作
glEnable(GL_TEXTURE_2D);   // 启用二维纹理
glDisable(GL_TEXTURE_2D); // 禁用二维纹理
在使用纹理前,必须载入纹理,利用以下函数可以载入一个纹理:

glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_BGR_EXT,GL_UNSIGNED_BYTE,PixelsData);//一共9个参数,第一个为GL_TEXTURE_2D,为2维纹理。第二个参数为“多重细节层次”,暂且将这个参数设置为零。第三个参数为采用颜色的分量数,可以调用参数GL_RGB,GL_RGBA。第4,5个参数是调用2维纹理的宽度和高度,很多版本的openGL可能需要宽高为2的整数倍,当这个要求无法满足时,使用gluScaleImage函数把图象缩放至所指定的大小,可以调用函数glGetIntegerv来获取最大纹理大小。第6个参数是纹理边框的大小,可以设置为0。最后三个参数与glDraoPixels的后三个参数一致。
GLint max;
glGetIntegerv(GL_MAX_TEXTURE_SIZE,&max);//将纹理最大调用值保存在max变量中。
纹理坐标的设置:
glBegin( /* ... */ );
     glTexCoord2f( /* ... */ );   glVertex3f( /* ... */ );//利用glTexCoord2f指定纹理图案的某个位置点(规定纹理坐标左下角坐标为(0,0),右上角坐标为(1,1)),这个点将变换到我需要绘制的三维空间上的某一个点,这个点的坐标由glVertex3f定义,这样就有一一对应的关系了
     glTexCoord2f( /* ... */ );   glVertex3f( /* ... */ );
     /* ... */
glEnd();
当然纹理也可以进行旋转平移等变换,这需要利用glMatrixMode(GL_TEXTURE)将变换矩阵切换到纹理矩阵,接着即可使用glRotatef(),glScalef(),glTranslate*()等函数进行变换了。
纹理参数:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//当一个纹理图像被应用到一个大小小于本身的空间时(即纹理图像中的多个像素被绘制到一个像素点上,譬如256*256的纹理应用到128*128的图像上)的处理方式,GL_LINEAR可以设置当前像素颜色是若干相邻像素颜色的加权平均。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//当纹理图像被应用到一个比它本身大的空间上的处理方式,同上。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//纹理第一维坐标在0到1之间,若坐标超过这个或者小于这个范围的处理方式。GL_REPEAT表示重复循环(0,0)至(1,1)上的图画
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);//设置纹理第二维坐标,设置方式同上
纹理对象:
载入一幅纹理需要比较长的时间,所以要尽量减少纹理的载入次数,利用纹理对象,可以在第一次绘制之前就载入它,以后就不需要载入了。我们可以把每一副纹理(包括纹理的像素数据,大小信息,参数设置等等)放到纹理对象当中,这样创建多个纹理对象来保存多副纹理。这样,绘制时只需指明究竟在使用哪一个纹理对象即可。
纹理对象和显示列表的相似之处在于:使用一个正整数来代表纹理对象的编号,并且可以调用glGenTextures()来分配纹理对象,以下是该函数的用法:
GLuint texture_id;
glGenTextures(1,&texture_id);//分配一个纹理对象的编号,该编号保存于texture_id中
GLuint texture_id[5];
glGenTexture(5,texture_id);//分配五个纹理对象的编号,保存于texture_id数组
对应于glGenTexture函数,glDeleteTextures用于销毁一个纹理对象。
分配了纹理对象的编号后,使用glBindTexture函数来指定“当前所使用的纹理对象”。之后就可以调用glTexImage函数指定纹理像素、glTexParameter指定纹理参数、glTexCoord*函数指定纹理坐标。若不用glBindTexture,后三个函数默认使用编号为0的纹理对象进行操作。
glBindTexture(GL_TEXTURE_2D,id);//第一个参数是需要使用纹理的目标,用二维纹理,指定为GL_TEXTURE_2D,第二个参数是需要调用的纹理编号。
GLuint texture_id[2];
glGenTextures(2,texture_id);
glBindTexture(GL_TEXTURE_2D,texture_id[0]);
//载入第一幅纹理
glBindTexture(GL_TEXTURE_2D,texture_id[1]);
//载入第二幅纹理
........
//在绘制时,切换到想要使用的纹理坐标即可
glBindTexture(GL_TEXTURE_2D,texture_id[0]);//指定为第一幅纹理
//使用该纹理
glBindTexture(GL_TEXTURE_2D,texture_id[1]);//指定为第二幅纹理
//使用该纹理

片段测试
片段测试用于测试每一个像素,只有像素通过所有测试才会被绘制。openGL测试的顺序是:裁剪测试->Alpha测试->模板测试->深度测试
1:裁剪测试,只有在窗口内的像素才会被绘制
glEnable(GL_SCISSOR_TEST);//启用裁剪测试。glDisable(GL_SCISSOR_TEST);禁用裁剪测试
glScissor(x,y,width,height);//指定一个位置在(x,y),宽度为width,高度为height的裁剪窗口(注意:opengl窗口坐标左下角(0,0),右上角(width,height))。这里注意这个函数和视口变换函数glViewport的区别,视口变换函数只是将画面所有内容缩放到一个规定大小的矩形区域内,而裁剪测试不会缩放,超出矩形范围的像素直接忽略。
2:Alpha测试,用于检查每个像素点的Alpha值,只有Alpha值满足条件的像素才会通过测试。
glEnable(GL_ALPHA_TEST);//开启Alpha测试 glDisable(GL_ALPHA_TEST);关闭Alpha测试
glAlphaFunc(GL_GREATER,0,5f);//该函数用于设置Alpha测试条件,参数GL_GREATER和0,5f代表大于Alpha值大于0.5则通过。参数还可以选取以下各值:
GL_ALWAYS(始终通过) GL_NEVER(始终不通过) GL_LESS(小于则通过) GL_LEQUAL(小于等于就通过) GL_EQUAL(等于则通过) GL_GEQUAL(大于等于则通过) GL_NOTEQUAL(不等于则通过)
3:模板测试,检查每个像素点的模板值,模板值满足一定条件才绘制像素。
首先,模板测试需要一个模板缓冲区,这个缓冲区是在初始化OPENGL时指定的。调用glutInitDisplayMode(GLUT_STENCIL);即可
glEnable(GL_STENCIL_TEST);//启用模板测试。glDisable(GL_STENCIL_TEST);禁用模板测试
glStencilFunc(GL_LESS,3,mark);//该函数用于设置模板测试条件,注意模板值只能为整数,函数前两个参数和glAlphaFunc参数一样,第三个参数mask表示只比较mask二进位制为1的位,设当前像素模板值为b,那么最终比较的是(b&mask)的值和模板测试值得关系。
glClear(GL_STENCIL_BUFFER_BIT);//可以复位所有像素得模板值,那么复位到那个值呢?可以调用下面得函数设置模板初始值。
glClearStencil(0);//设置0为模板初始值,该函数类似于glClearColor
glStencilOp(fail,zfail,zpass);//每个像素得“模板值”会根据模板测试和深度测试的结果进行改变。该函数三个参数,第一个参数代表模板测试失败后该像素模板值如何变化,第二个参数代表像素通过模板测试但没通过深度测试后值如何变化,最后一个参数代表通过了深度测试后值该如何变化。
上述函数三个参数可以有如下的几种选择:
GL_KEEP(不改变值,也是默认值) GL_ZERO(回零) GL_REPLACE(使用测试条件设定的模板值来替换当前像素的模板值) GL_INCR(增加1,如果达到最大值,则不变) GL_INCR_WRAR(增加1,如果达到最大值,则从0开始) GL_DECR(减少1,已经是0则不变) GL_DECR_WRAR(减少1,已经是0,则设置为最大值) GL_INVERT(按位取反)。
在多边形中,允许多边形正面和背面使用不同的模板测试条件和模板值改变方式。可以利用以下函数:
glStencilFuncSeparate(GL_FRONT,GL_LESS,3,mark);//第一个参数代表这是对多边形正面的测试条件,后三个参数与glStencilFunc类似
glStencilOpSeperate(GL_FRONT,fail,zfail,zpass);//介绍同上。
4:深度测试
glutInitDisplayMode(GLUT_DEPTH);//明确指定要求使用深度缓冲区
glEnable(GL_DEPTH_TEST);//启用深度测试。glDisable(GL_DEPTH_TEST);//禁用深度测试
glDepthFunc(GL_LESS);//判定像素的深度值是否符合要求就调用该函数,参数为设置条件,参数类型与Alpha测试当中的8种一样。
glDepthMask(GL_FALSE);//设置深度测试状态为可读不可写状态。可以再调用参数GL_TRUE恢复可写状态。

openGL工作流程:输入像素数据以及顶点数据,两种数据进行操作后,进行光栅化,得到片段fragment,经过片段处理,绘制到帧缓冲区。整个绘制的过程也可以逆向传送,转化为像素数据。

利用顶点数组减少绘制工作
在绘制立体图像的时候,如果直接利用vertex*类函数的话比较麻烦且容易绘制失误,尽量使用顶点数组。举个例子,以下要绘制一个正方体的做法:可以先把正方体的6个顶点的3维数据保存在顶点数组当中,现在还要绘制6个面,每个面都需要正方体其中4个顶点,故还可以建立一个序号数组,把绘制每一个面需要的顶点序号保存于序号数组当中:
static const GLfloat vertex_list[][3]={
-0.5f,-0.5f,-0.5f,//写下每一个顶点的3维坐标位置
0.5f,-0.5f,-0.5f,
.......
}
static const GLint index_list[][4]={
0,2,3,1,//每一个面需要四个顶点,写下四个顶点在顶点数组中的序号位置即可
0,4,6,2,//注意编号顺序,正面逆时针,反面顺时针
......
}
glBegin(GL_QUADS);
for(int i=0;i<6;i++)
for(int j=0;j<4;j++)
glVertex3fv(vectex_list[index_list[i][j]]);
glEnd();
因为我们定义了正面逆时针顺序,反面顺时针顺序,绘制前调用以下代码:
glFrontFace(GL_CCW);//逆时针代表正面
glEnable(GL_CULL_FACE);//开启剔除功能
glCullFace(GL_BACK);//剔除多边形反面,即不绘制多边形反面,提高运行效率
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);//只显示线条,不进行填充
上面关于顶点数组的操作还可以更加简便的调用函数:
glEnableClientState(GL_VERTEX_ARRAY);//启用顶点数组
glVertexPointer(3,GL_FLOAT,0,vertex_list);//指定了顶点数组的位置。其中第一个参数3代表维度,GL_FLOAT代表每一维度的数据类型,0是"stride"参数,表示从一个数据的开始到下一个数据的开始,所间隔的数字。第四个参数指明了数组实际位置。
glDrawElements(GL_QUADS,24,GL_UNSIGNED_INT,index_list);//根据序号数组index_list中的序号,查找相应的顶点并完成绘制。GL_QUADS代表绘制四边形,24代表要绘制的顶点个数,GL_UNSIGNED_INT代表序号的数据类型,第四个即序号列表存储位置。
顶点数组实际可以是多个数组,顶点坐标,纹理坐标,法线向量,顶点颜色等等,每一个属性可以指定一个数组来存储,之后用统一的序号来进行访问,代表同一个顶点的元素信息。
利用glEnableClientState();单独开启并关闭每一个数组的使用,每一个数组的参数类型有:
GL_VERTEX_ARRAY(顶点位置数组) GL_COLOR_ARRAY(顶点颜色数组) GL_NORMAL_ARRAY(顶点法线向量数组) GL_TEXTURE_COORD_ARRAY(顶点纹理坐标数组)
开启相应的数组以后,以下函数可以用来指定数组所在位置:
glVertexPointer();glColorPointer(); glNormalPointer(); glTexCoordPointer();
混合数组:如果同时需要使用颜色数组,顶点坐标数组,纹理数组等等,可以把它们混合到一个数组当中,这个数组称为混合数组。

  GLfloat arr_c3f_v3f[] = {
  1,0,0,0,1,0,
  0,1,0,1,0,0,
  0,0,1,-1,0,0,
  };
  GLuint index_list[] = { 0,1,2 };
  glInterleavedArrays(GL_C3F_V3F, 0, arr_c3f_v3f);//该函数用于指定混合数组,
  glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, index_list);//根据序号数组的序列,查找相应顶点并绘制

  顶点数组和显示列表的区别:显示列表的数据已经全部存放于服务器端,也就是说每次调用显示列表,数据直接从服务器端拿,而不需要再从内存取出,速度比较快,但是又比较死板,数据不能随意进行修改。而每次调用顶点数组,每次都需要把数据从内存里面取出,比较花时间,但是由于内存中的数据可以随意进行修改,所以顶点数组比较灵活,但速度较慢。

原文地址:https://www.cnblogs.com/ZefengYao/p/9261005.html