【问题标题】:Capping alpha for sprite blending为精灵混合封顶 alpha
【发布时间】:2015-07-24 14:53:52
【问题描述】:

在现代 OpenGL 中,我为每个精灵使用带纹理的四边形绘制一系列相邻的精灵(如画笔描边)。在不累积 alpha 值的情况下,我可以使用什么技术来绘制精灵?

为了清楚起见,让我举个例子。

假设我的精灵是一个半透明的圆圈,例如:

如果我绘制两个相邻的精灵,我会得到:

这很正常,虽然我想得到的是这样的:

结果的 alpha 值是 source 和 dest 的 alpha 的最大值,就好像它们是同一可视层的一部分。

我认为这涉及到我的blend function。 目前是:

 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

我可以使用哪种混合功能或其他技术来达到预期的效果?

【问题讨论】:

    标签: c++ opengl glfw opengl-3


    【解决方案1】:

    (Ab)使用模板缓冲区:

    1. 将模板缓冲区清除为 0xff
    2. 对于每个圆圈,仅将模板缓冲区为 0xff 的颜色和模板缓冲区写入(和混合)。如果模板和深度测试成功,则将片段的模板值设置为零。

    这样您只能写入(和混合)一个颜色像素一次,直到您再次清除模板缓冲区。

    例子:

    #include <GL/glut.h>
    
    void quad()
    {
        glBegin( GL_QUADS );
        glVertex2i( -1, -1 );
        glVertex2i(  1, -1 );
        glVertex2i(  1,  1 );
        glVertex2i( -1,  1 );
        glEnd();
    }
    
    void display()
    {
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
        glOrtho( -2, 2, -2, 2, -1, 1 );
    
        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity();
    
        // clear stencil buffer to all 1s
        glClearStencil( 0xff );
        glClear( GL_STENCIL_BUFFER_BIT );
    
        // turn on stencil testing & make sure we don't mask out any bits
        glEnable( GL_STENCIL_TEST );
        glStencilMask( 0xff );
    
        // only allow fragments through to the color/depth buffers if
        // the stencil buffer at that point is 0xff
        glStencilFunc( GL_EQUAL, 0xff, 0xff );
    
        // if the stencil/depth tests succeed for a fragment, 
        // zero out the stencil buffer at that point;
        // that way you can only write to a color buffer pixel once
        glStencilOp( GL_KEEP, GL_KEEP, GL_ZERO );
    
        glEnable( GL_BLEND );
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
        glPushMatrix();
        glTranslatef( -0.5, -0.5, 0 );
        glColor4ub( 255, 0, 0, 128 );
        quad();
        glPopMatrix();
    
        glPushMatrix();
        glTranslatef( 0.5, 0.5, 0 );
        glColor4ub( 255, 0, 0, 128 );
        quad();
        glPopMatrix();
    
        glutSwapBuffers();
    }
    
    int main( int argc, char **argv )
    {
        glutInit( &argc, argv );
        glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_STENCIL );
        glutInitWindowSize( 600, 600 );
        glutCreateWindow( "GLUT" );
        glutDisplayFunc( display );
        glutMainLoop();
        return 0;
    }
    

    【讨论】:

    • 感谢您花时间写详细的例子,我试试看。
    • @Rotem:注释掉glEnable( GL_STENCIL_TEST ) 行,看看没有模板缓冲区的重叠混合是什么样子。
    • 请注意,在 Modern GL 中,您实际上需要测试 alpha 和 discard 完全透明的片段,否则您仍将执行模板测试。
    • 假设你从一个纹理中采样,在你的片段着色器中你会得到类似vec4 sampledColor = texture(yourSampler, texCoord);的东西。您需要添加if (sampledColor.a == 0.0) discard;
    • 这个答案并没有解决输出最大值的问题,而是只输出第一个透明对象。对对象进行排序,以便首先渲染最不透明的对象可以解决此问题,除非一个对象可以具有多个 alpha 值。
    【解决方案2】:

    这就是我最终要做的。很难将其称为答案,因为我稍微更改了问题的参数,但我想我会为后代提及它。

    我没有使用透明精灵,而是使用完全不透明的精灵。

    然后我将它们渲染为纹理,然后以所需的不透明度绘制该纹理。

    【讨论】:

      猜你喜欢
      • 2018-02-14
      • 2010-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多