OpenGL模版小案例分析

Posted xiaonanxia

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;                      
"
        "  attribute vec4 a_color;  
                       "
    
    "
#ifdef GL_ES
"
    "varying lowp vec4 v_fragmentColor;"
    "varying mediump vec2 v_texCoord;"
    "
#else
"
       " varying vec4 v_fragmentColor;"
    "varying vec2 v_texCoord;"
    "
#endif
"
    
    
        "     void main()   {                     
"
        "       gl_Position =  a_position;                           
"
         "          
"
    "              v_fragmentColor=  a_color ;     
"
        "        }                                
";
        //片段着色器
        //写入的这个变量将被写入颜色缓冲区
        char fShaderStr[] =
        "                          
"
        "                           
"
        "
#ifdef GL_ES
"
         "precision lowp float;"
        " 
#endif
"
    
        " varying vec4 v_fragmentColor; 
"
        "                          
"
        "void main()                                  
"
        "{                                            
"
        "   gl_FragColor = v_fragmentColor ;  
"
        "}                                            
";
    
    
    
         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,所以这部分三角形绘制了出来

 

以上是关于OpenGL模版小案例分析的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL ES 学习教程(十三) Stencil_TEST(模板缓冲测试)

使用Visual Studio Code自定义代码模版

使用 Git 来管理 Xcode 中的代码片段

OpenGL片段着色器不照亮场景

片段着色器中未使用纹理数据 - OpenGL

带有顶点/片段着色器的光。使用不同的变量。 (openGL)