2

I am trying to develop a particle system in C++ using OpenGL, and I am confused about how blending works. I am trying to use additive blending, and from my understanding, calling the glBlendFunc function with the following arguments:

glBlendFunc(GL_SRC_ALPHA, GL_ONE);

Will cause the following when you try to render something: It will take the R,G,B color calculated by the fragment shader (source color), multiply that by the alpha value calculated by the fragment shader (source alpha), and then add that to the R,G,B color that already exists in the frame buffer (dest color). But if this is true, then a black color, where (R,G,B,A) = (0,0,0,1), calculated by the fragment shader should leave the existing frame buffer color (dest color) unchanged since it is multiplying the source color value of 0 by the source alpha value of 1, which should obviously always yield 0, and then that 0 is added to the existing frame buffer color (dest color) which should leave it unchanged...right?

However, when I do this, instead of leaving the color unchanged, it actually makes it lighter, as shown here:

In this picture, the environment and sword are rendered with normal blending, and then the square particles are rendered around the sword with glBlendFunc(GL_SRC_ALPHA, GL_ONE); using a fragment shader that ALWAYS outputs (R,G,B,A) = (0,0,0,1). There are many particles rendered, and you can see that as more particles overlap, it gets brighter. When I switch the alpha output of the shader from 1 to 0 (source alpha), then the particles disappear, which makes sense. But why are they still visible when source color=1 and source alpha=0?

Here is the exact function I call to render the particles:

void ParticleController::Render()
{
    GraphicsController* gc = m_game->GetGraphicsController();
    ShaderController* sc = gc->GetShaderController();
    gc->BindAttributeBuffer(m_glBuffer);
    ShaderProgram* activeShaderProgram = sc->UseProgram(SHADER_PARTICLE);
    glDepthMask(false);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);

    gc->GetTextureController()->BindGLTexture(TEX_PARTICLES);

    activeShaderProgram->SetUniform(SU_PROJ_VIEW_MAT, gc->GetProjectionMatrix() * gc->GetViewMatrix() * gc->GetWorldScaleMatrix());

    activeShaderProgram->SetUniform(SU_LIGHT_AMBIENT, m_game->GetWorld()->GetAmbientLight());

    activeShaderProgram->SetUniform(SU_TIME, m_game->GetWorld()->GetWorldTime());

    CheckForOpenGLError();
    m_pa.GLDraw();
    CheckForOpenGLError();

    gc->BindAttributeBuffer_Default();
    CheckForOpenGLError();

    glDepthMask(true);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

And these are the last 4 lines of my fragment shader, ensuring that the particle color output (R,G,B,A) is always = (0,0,0,1):

fColor.r = 0.0;
fColor.g = 0.0;
fColor.b = 0.0;
fColor.a = 1.0;

Is there something I am missing?

Jeremy
  • 145
  • 2
  • 12
  • Your expectations seem correct. Are you calling `glBlendEquation` with anything other than `GL_FUNC_ADD`? – GuyRT Aug 12 '15 at 10:41
  • Sorry - actually I don't think any of the other `glBlendEquation` modes will produce your output. Are you absolutely sure `glBlendFunc(GL_SRC_ALPHA, GL_ONE)` is in effect when you issue your draw call? – GuyRT Aug 12 '15 at 10:46
  • @GuyRT I added the exact code I use to render the particles. On the 6th line of the render function, I call `glBlendFunc(GL_SRC_ALPHA, GL_ONE);` And `glBlendFunc()` doesnt get called again until the end of the function after all the `glDrawArrays()` calls. – Jeremy Aug 13 '15 at 02:01
  • @GuyRT Does it matter that I am using render to texture with a floating point color buffer in order to implement HDR color? The color buffer data type is defined as GL_RGBA16F. – Jeremy Aug 13 '15 at 02:08
  • @GuyRT I just tested it, and I think it does have something to do with the floating point color buffer. I changed the rendered texture from `GL_RGBA16F` To: `GL_RGBA` And now it has the expected behavior (except I obviously don't have HDR). But why?? And how can I get it to work properly with a floating point frame buffer? – Jeremy Aug 13 '15 at 02:21
  • *Despite the apparent precision of the above equations, blending arithmetic is not exactly specified, because blending operates with imprecise **integer color values**. However, a blend factor that should be equal to 1 is guaranteed not to modify its multiplicand, and a blend factor equal to 0 reduces its multiplicand to 0.* ([glBlendFunc](https://www.opengl.org/sdk/docs/man/html/glBlendFunc.xhtml)) Sounds like blending only happens on integral colour values. Looks like you'd need to write your own shader for HDR (buffer opaque pass, combine in blend shader). – BeyelerStudios Aug 13 '15 at 10:10
  • Scratch my comment, [OpenGL 3.0](https://www.opengl.org/wiki/Floating_point_and_mipmapping_and_filtering) and later should support all blending operations on float buffers too... – BeyelerStudios Aug 13 '15 at 10:29

0 Answers0