OpenGL超级宝典学习笔记——其他缓冲区技巧
使用目标缓冲区
OpenGL并不是直接在屏幕上绘制图元的,而是先渲染到缓冲区中,然后再交换到屏幕上。颜色缓冲区有两个一个是前颜色缓冲区,一个是后颜色缓冲区。OpenGL默认是在后颜色缓冲区中绘制,然后再通过glutSwapBuffers(或者操作系统的缓冲区交换函数)交换前后缓冲区。我们也可以直接在前缓冲区中进行绘制,这样我们可以看到一些绘制的动画效果。
使用前缓冲区的第一个方法是调用
void glDrawBuffer(GLenum mode);
mode参数为GL_FRONT,OpenGL就会在前缓冲区中进行绘制。
第二种方法是不适用双缓冲区机制。
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);这个是使用双缓冲区和RGB颜色缓冲区。
在glut中可以简单地忽略GLUT_DOUBLE参数。glutInitDisplayMode(GLUT_RGB);来实现只使用前缓冲区渲染。进行单缓冲区渲染时,如果希望绘制结果显示到屏幕上,需要调用glFlush();或glFinish();函数。
static void RenderScene() { static GLdouble dRadius = 0.1; static GLdouble dAngle = 0.0; if (dAngle == 0.0) { glClear(GL_COLOR_BUFFER_BIT); } glColor3f(0.0f, 1.0f, 0.0f); //画点 glBegin(GL_POINTS); glVertex2f(dRadius * cos(dAngle), dRadius * sin(dAngle)); glEnd(); dRadius *= 1.01; dAngle += 0.1; if (dAngle > 30.0) { dRadius = 0.1; dAngle = 0.0; } glFlush(); } //定时绘制 static void Timer(int value) { glutTimerFunc(50, Timer, 0); glutPostRedisplay(); }
操作深度缓冲区
在glut中请求深度缓冲区,只需在其初始化显示模式的时候,加上GLUT_DEPTH位标记:
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
开启深度测试:
glEnable(GL_DEPTH_TEST);
即使深度测试未被开启。opengl还是会往深度缓冲区中写深度值。有时候你需要暂时关掉往深度缓冲区中写值。可以调用:
void glDepthMask(GLboolean mask);
设置mask这个参数值为GL_FALSE来达到禁用往深度缓冲区里写值。使用GL_TRUE则重新启动往深度缓冲区中写值。
使用剪刀进行裁剪
一种提高渲染性能的方式是只渲染屏幕上产生变化的那一部分。你也许需要限制Opengl只渲染一小块矩形区域。OpenGL允许在窗口中指定一个裁剪矩形。打开裁剪测试
glEnable(GL_SCISSOR_TEST);
关闭裁剪测试glDisable(GL_SCISSOR_TEST);指定裁剪框,一窗口坐标(像素)形式指定。
void glScissor(GLint x, GLint y, GLsizei width, GLsizei height);
x和y指定了裁剪框的左下角坐标,width和height分别指定了宽带和高度。
static void RenderScene() { glClear(GL_COLOR_BUFFER_BIT); //设置裁剪框 glScissor(100, 100, 400, 400); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); //启用裁剪功能 glEnable(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT); glScissor(200, 200, 200, 200); glClearColor(1.0f, 1.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); glFlush(); }
使用模板缓冲区
如果我们希望使用一个模板突然来渲染一个不规则的形状。在OpenGL中可以使用模板缓冲区。
首先我们需要请求一个模板缓冲区,在GLUT中可以使用GLUT_STENCIL位来初始化显示模式。
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_STENCIL);
在现代的OpenGL实现中,模板操作时被硬件加速过的。我们可以使用glEnable/glDisable来打开或关闭模板测试.
glEnable(GL_STENCIL_TEST);
当打开模板测试的时候,在通过模板测试的地方才会进行绘制。设置模板测试的函数:
void glStencilFunc(GLenum func, GLint ref, GLuint mask);
第一个参数func来设置比较函数。可以是GL_NEVER, GL_ALWAYS, GL_LESS, GL_GREATER, GL_LEQUAL, GL_EUQAL, GL_GEUQAL 和GL_NOTEQUAL。这个参数值告诉Opengl如何去和你传进来的第二个参数ref进行比较。另外你还可以设置掩码值mask。这个掩码值会和ref模板缓冲区中的值进行与操作。即mask先和这两个值进行与操作 后再进行比较。
创建模板图案
开始绘图之前,我们要先清除模板缓冲区。这与glClear函数清除颜色和深度缓冲区的方法是一样的,只不过使用的位掩码是GL_STENCIL_BUFFER_BIT。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glClearStencil(GLint s);这个函数来设置清除模板缓冲区时使用的值。
在启用了模板测试之后,渲染命令就使用glStencilFunc函数的参数与存储在模板缓冲区中的值进行测试。根据模板测试的结果,来判断值应该被写入或被丢弃。在测试的过程中,模板缓冲区本身也可以被修改,进入模板缓冲区的值取决于glStencilOp函数设置的参数。
void glStencilOp(GLenum fail, Glenum zfail, GLenum zpass);
第一个参数告诉opengl,如果模板测试失败,模板缓冲区的值应该如何被修改。第二个参数和第三个参数则说明当通过模板测试且深度测试失败或当通过模板测试且深度测试通过时,模板缓冲区的值应该如何被修改。这些参数的合法值包括GL_KEEP(保持当前值), GL_ZERO(设置为0), GL_REPLACE(用参考值即glStencilFunc设置的ref值代替), GL_INCR(增加这个值), GL_DECR(减少这个值), GL_INVERT(将这个值进行反转),GL_INCR_WRAP(循环增加), GL_DECR_WRAP(循环减少).
例子:
static void RenderScene() { GLdouble dRadius = 0.1; //最初的螺旋半径 GLdouble dAngle; glClearColor(0.0f, 0.0f, 1.0f, 0.0f); //使用0值来清除模板缓冲区 glClearStencil(0.0f); glEnable(GL_STENCIL_TEST); //清除模板缓冲区 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //先初始化模板,让所有的模板测试都不通过,只是改变模板缓冲区的值 glStencilFunc(GL_NEVER, 0x0, 0x0); glStencilOp(GL_INCR, GL_INCR, GL_INCR); //用白线绘制螺旋模型 glColor3f(1.0f, 1.0f ,1.0f); glBegin(GL_LINE_STRIP); for (dAngle = 0; dAngle < 400.0; dAngle += 0.1) { glVertex2d(dRadius * cos(dAngle), dRadius * sin(dAngle)); dRadius *= 1.002; } glEnd(); //现在允许进行绘图,但不包含那些模板模型是0x1的地方 glStencilFunc(GL_NOTEQUAL, 0x1, 0x1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); //绘制红色的反弹方块 glColor3f(1.0f, 0.0f, 0.0f); glRectf(x, y, x + rsize, y - rsize); glutSwapBuffers(); }