Closing alpha for blending sprites

In modern OpenGL, I paint a series of adjacent sprites using a textured square for each sprite (as in the case of a brush). What technique can I use to paint sprites without accumulating alpha data?

To be clear, let me show you an example.

Let's assume my sprite is a semi-transparent circle, as such:
enter image description here

If I draw two adjacent sprites I would get this:
enter image description here

This is very fine, although I want to get this:
enter image description here

If the alpha value of the result is the maximum of the alpha of the source and the dest, as if they were part of the same visual layer.

I'm guessing it has to do with the blend function . Currently these are:

 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

      

What mixing function or other technique can be used to achieve the desired result?

+3


source to share


2 answers


(Ab) use a stencil buffer:

  • Clear stencil buffer to 0xff
  • Circle forach, just write (& blend) to color and stencil buffers where the stencil buffer is 0xff. If the stencil and depth tests have undergone a successful assertion of the stencil value for fragment numbering.

This way you can only & blend the color pixel once, until you clear the stencil buffer again.



Example:

#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;
}

      

+2


source


This is what I ended up doing. It's hard to call this an answer since I changed the parameters of the question a bit, but I thought I mentioned it for posterity.

Instead of using transparent sprites, I use fully opaque sprites.



Then I create them with a texture and then paint this texture with the desired opacity.

+1


source







All Articles