OpenGL模版小案例分析
下面的案例通过模版实现三角形截取的功能,代码如下:
void draw(){ GLuint programObject; GLfloat vVerticessmall[] = { 0.0f, 0.25f, 0.0f, -0.25f, -0.25f, 0.0f, 0.25f, -0.25f, 0.0f }; GLfloat vVertices[] = { 0.0f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f }; GLfloat vColorssmall[] = { 0.0f, 0.5f, 0.0f,1.0f, 0.0f, 0.5f, 0.0f,1.0f, 0.0f, 0.5f, 0.0f,1.0f, }; GLfloat vColorsbig[] = { 0.5f, 0.5f, 0.0f,1.0f, 0.5f, 0.5f, 0.0f,1.0f, 0.5f, 0.5f, 0.0f,1.0f, }; //这里视口的像素要和 分配的纹理大小一致,这样才可以绘制全图, //注意这里的屏幕大小是以 纹理大小 为准了,与手机屏幕大小没有关系 glViewport(0,0,1136,640); glClearColor(1.0,1.0,1.0,1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); char vShaderStr[] = " attribute vec4 a_position; \n" " attribute vec4 a_color; \n " "\n#ifdef GL_ES\n" "varying lowp vec4 v_fragmentColor;" "varying mediump vec2 v_texCoord;" "\n#else\n" " varying vec4 v_fragmentColor;" "varying vec2 v_texCoord;" "\n#endif\n" " void main() { \n" " gl_Position = a_position; \n" " \n" " v_fragmentColor= a_color ; \n" " } \n"; //片段着色器 //写入的这个变量将被写入颜色缓冲区 char fShaderStr[] = " \n" " \n" "\n#ifdef GL_ES\n" "precision lowp float;" " \n#endif\n" " varying vec4 v_fragmentColor; \n" " \n" "void main() \n" "{ \n" " gl_FragColor = v_fragmentColor ; \n" "} \n"; programObject= esLoadProgram ( vShaderStr, fShaderStr ); glUseProgram ( programObject ); // glEnable(GL_DEPTH_TEST); glEnable(GL_STENCIL_TEST); s_layer++; //左移s_layer位,一个模版点8位的话,最多可以移动8次 GLint mask_layer = 0x1 << s_layer; //得到前一位,比如如果s_layer=100,那么mask_layer_l=011 GLint mask_layer_l = mask_layer - 1; //两个相与,得到 111 _mask_layer_le = mask_layer | mask_layer_l; /* 设置模板缓冲区的写入掩码: 只允许mask位被写入 glStencilMask控制模板平面中各个位的写入。 掩码的最低有效n位,其中n是模板缓冲区中的位数,指定掩码。 只要出现一个1,模板缓冲区中的相应位就可写。 如果出现0,则该位被写保护。 最初,所有位都被启用以进行写入。 */ //这个方法很关键,控制被写入的位数,比如mask_layer=10,那么只能在第二位写入数据,其余的不动 glStencilMask(mask_layer); glStencilFunc(GL_NEVER, mask_layer, mask_layer); glStencilOp(GL_REPLACE , GL_KEEP, GL_KEEP); /*****************屏蔽的部分***********************/ //glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0,vVertices); // glEnableVertexAttribArray ( 0 ); // glVertexAttribPointer ( 1, 4, GL_FLOAT, GL_FALSE, 0, vColorsbig ); // glEnableVertexAttribArray ( 1 ); // // glDrawArrays ( GL_TRIANGLES, 0, 3 ); //再次向左移动一位 s_layer++; mask_layer = 0x1 << s_layer; mask_layer_l = mask_layer - 1; _mask_layer_le = mask_layer | mask_layer_l; //比如如果是100,那么就只能向第三位写入数据 glStencilMask(mask_layer); glStencilFunc(GL_NEVER,0xFF, 0xFF); glStencilOp(GL_REPLACE , GL_KEEP, GL_KEEP); // 绘制小三角形 //通过绘制,因为之前设置的Never,所以这次只是替换mask_layer到模版缓冲区,因为之前设置了 glStencilMask //所以只能向数字为1的地方写入,如果mask_layer=100,那么只能吧1写入到第三位 glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVerticessmall ); glEnableVertexAttribArray ( 0 ); glVertexAttribPointer ( 1, 4, GL_FLOAT, GL_FALSE, 0, vColorssmall ); glEnableVertexAttribArray ( 1 ); glDrawArrays ( GL_TRIANGLES, 0, 3 ); //这里的条件是满足全部的值,比如111 glStencilFunc(GL_EQUAL, _mask_layer_le,_mask_layer_le); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); //绘制大三角形 glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0,vVertices); glEnableVertexAttribArray ( 0 ); glVertexAttribPointer ( 1, 4, GL_FLOAT, GL_FALSE, 0, vColorsbig ); glEnableVertexAttribArray ( 1 ); glDrawArrays ( GL_TRIANGLES, 0, 3 ); s_layer--; s_layer--; glDisable(GL_STENCIL_TEST); }
运行程序,发现什么也没绘制
然后把标红的屏蔽代码打开,运行,绘制如图所示:
分析原因:
大部分代码都有注释,简单说一下:
通过上面代码的运行,_mask_layer_le的二进制数最终为00000011,也就是绘制的时候,模版缓冲区的每一像素点的值为00000011,才能运行继续绘制,如果屏蔽掉那段代码,那么模版缓冲区中将只有00000000和00000010的数据,没有符合条件的,所以没有绘制出来,反之,会使模版缓冲区中一部分数据为00000011,所以这部分三角形绘制了出来