It’s not blending, it’s doing the premultiplication on the fly, rather than offline or at texture creation time. Anyway, it can only be applied in 2D rendering (no magnification/minification), so it’s not a general solution.
:o hugs delt0r that explains a lot! especially the whole ‘ONE’/‘ONE_MINUS_SRC_ALPHA’, since I never understood that stuff either
Always do the premultiplication on the source data before it gets to the shader, i.e. it needs to be that way when you upload it to GL. A lot of 2D games do scaling and layering and this is only really solved by doing it this way. And of course you don’t need to use any fancy shader for it to work.
Also you should realise that you can and need to use premultiplied alpha on all other rendering as well in your 2D graphics effects. This means if you were going to use the totally wrong and busted method of:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // NEVER USE THIS
glColor4f(1.0f, 0.5f, 0.25f, 0.5f);
// render some lines or a rectangle or something here...
you actually need to premultiply your colour there, too:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.5f, 0.25f, 0.125f, 0.5f);
I can’t stress highly enough how WRONG using glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) is. NEVER USE IT. Just about every example ever on the internet and in books uses this blend function, and it is wrong wrong wrong.
Cas
but I use textures with transparent background using PNGs…
@princec - I regret I hath but one medal to lay down …
Absolutely agree, always use pre-multiplied alpha. I’ve said this a few times on here myself, and it’s usually met with mild bemusement. I read a great article a few years back that outlined all the various pitfalls, but can’t seem to find it any longer (though my old mate Google brings up a few others that aren’t as comprehensive). If you know of any good articles on this, please share links - I guess the ins and outs of this would make a useful wiki article.
Embarrassingly I only found out about all this myself about 2 years ago. I think the link I was reading at the time was this blog on MSDN by Shawn Hargreaves.
Cas
I have to admit that other than the niche case of doing regular blending and additive blending in one image I don’t really see the need to use pre-multiplied alpha everywhere. You lose flexibility to do some of the more interesting alpha tricks at runtime and you probably have to add some kind of extra build step. Plus it confuses the heck out of artists, so you either get lower quality art or you have to keep running around after them fixing stuff because they made their art wrong.
Maybe someone could have a proper stab at explaining the actual concrete benefits to using pre-multiplied everywhere?
The reasons given in the linked article:
Image composition and filtering were what did it for me. It made an instantly noticeable improvement in graphics that had been bugging me for years - when we composited several sprites over each other they always seemed to end up with a greyish border around them all eventually. Then I discover it’s because we’d been doing it wrong.
There’s absolutely no reason not to switch to the correct method, right now, today. The “old” method is simply wrong, and always has been. As you’re applying premultiplication at texture upload time the artist never has to know about it either - they carry on working as per normal.
Cas
I always solve 1 + 2 by ‘bleeding’ the colour of sprites for any non-alpha-zero texels. That produces more sane data (in my head) as the alpha and colour data are still orthogonal. I’ve also never seen a proper breakdown of ‘it’s more correct’ with actual observable differences that can’t be solved by bleeding the rgb channels. Everywhere always just does some hand-wavy ‘it’s just better stupid’.
4 - I never use DXT because I hate the artifacts.
Which only leaves 3 - which is a useful trick but comes at the expense of being able to do other tricks and confuses artists. So as far as I’m concerned it’s just a matter of preference.
I’m really not sure why you’re bringing artists into the equation… Chaz never even knew I’d made the change. Everything just suddenly looked better one day.
Cas
As you point at additive blending for everything, how exactly do you subtract color from the framebuffer, like you do with regular blending…?
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) has its uses…
Oops, missed your bit about doing the multiply at upload time, yeah that’s a nice way of handling it. But it still doesn’t produce any tangible benefits that I can see.
@Riven - to be sure it’s got a use but just not the use that everyone thinks it has.
@OrangyTang - basically why muck around with bleeding pixels and other hax when you can just use the correct blending mode and fix the edge artifacts automatically and get your glow and transparent particles done using the same shader/ffpipeline functions?
Cas
The problem with regular blending is terrible color banding issues (see my YUNPM library, where I abuse it to create a blur)
Meh. Now we’re back to hand-wavey arguments about what’s more ‘correct’. Yet by colour bleeding I’ve maintained the orthogonality of the colour and alpha data, which is important as soon as you’re doing anything other than straight blitting. Which is why I see this as firmly in swings-and-roundabouts territory, rather than “you must use pre-multiplied alpha”.
Don’t get me wrong, this is for straight blitting. If you’re doing something fancypants that is not sprite/particle related then assuredly you might have other uses for the other blending mode. But my guess is you are doing sprites and glowy particles, and if that’s the case, you want to do it right.
Cas
Composition was in particular key for me. If you’re ever doing layered composition, rendering to a transparent texture first, then pre-multiplied is essential to get the right result.
Some other useful blend modes are not possible (shy of shaders) without pre-multiplied data as well - Multiply in particular.
Just realised that one of the posts I read a while back that I found useful was the TomF one in the OP’s post - just his link was broken by the forum!
What exactly do you mean by subtract? Actually, I think that question is the nub of why people don’t get this - standard blending should be an additive / accumulative process, and there’s a reason all blend modes (PorterDuff, etc.) are expressed in terms of pre-multiplied alpha. The blend function you give isn’t an Add blend though - if you draw fully opaque black on white you’ll end up with black (GL_ONE_MINUS_SRC_ALPHA on dst).
If that isn’t a flamebait, I don’t know what is…
Colour “subtraction” is still being performed on the framebuffer - the destination factor is still the same GL_ONE_MINUS_SRC_ALPHA as you might have used before. The alpha component of the texture is still the same as it was; it is now describing effectively how much of the framebuffer to show through the sprite. So at 255, that’s none; the existing pixels will have no bearing on the final colour.
Cas
@riven - definitely not my intention. I’m sorry that you feel everything I’m saying atm is a criticism. It’s honestly not meant that way.