Background
OpenGL blend funcs are just a means of specifying a mathematical formula as follows:
src
: the output from your fragment shader.
dst
: the colour in the framebuffer.
sfactor
: multiply src
by this.
dfactor
: multiply dst
by this.
- And add the two results together.
(As a simplifying assumption I'm ignoring blend equation, blend func separate and multiple render targets, and also assuming that you don't care about destination alpha).
So if we look at your two blend funcs we see that they work out as follows:
glBlendFunc (GL_SRC_ALPHA, GL_ONE) = src * src.a + dst * 1
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) = src * src.a + dst * (1 - src.a)
The objective is to find a way to use a single blend func for everything.
I'm going to assume, for the purposes of this answer, that your fragment shader writes it's output to gl_FragColor
. If it doesn't, just replace any references to gl_FragColor
in the remainder of this answer with whatever you do write to.
Let's repeat the two blend funcs again:
src * src.a + dst * 1
src * src.a + dst * (1 - src.a)
The only difference between the two is the value used for dfactor
, and it's (1 - src.a)
in the latter, so if we can modify our fragment shader to output 0 for src.a
in the former case, then the two blend funcs become the same (because 1 - 0 = 1).
However, we see that src.a
is also used as sfactor
in both, so we can't modify src.a
without also affecting that.
Let's see if we can find a way of modifying the fragment shader to remove that restriction. Since we don't care about destination alpha we can just do this:
gl_FragColor.rgb *= gl_FragColor.a;
After having done that, the two blend funcs become:
glBlendFunc (GL_ONE, GL_ONE)
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
Or:
src * 1 + dst * 1
src * 1 + dst * (1 - src.a)
So the only remaining thing is to find a means of setting src.a
to 0 in the former case; something like this in your fragment shader:
gl_FragColor.rgb *= gl_FragColor.a;
if (altBlend) gl_FragColor.a = 0;
So we want altBlend
to evaluate to true
in cases where you use GL_ONE, GL_ONE
blending, or false
in cases where you use GL_ONE, GL_ONE_MINUS_SRC_ALPHA
blending, and we have the result; we can now use a single blend func for all drawing:
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Or:
src * 1 + dst * (1 - src.a)
And in cases where src.a
is 0 this is exactly equivalent to:
src * 1 + dst * (1 - 0)
Or:
src * 1 + dst * 1
Or:
glBlendFunc (GL_ONE, GL_ONE);
So all that's remaining is how to set the value of altBlend
, and how you do that is entirely up to you. You could set an additional vertex attrib that you pass along to your fragment shader, you could bind an additional texture and sample from it for the different types of objects, or you could do something entirely different; it all depends on which is most appropriate for the rest of your code.