Welcome to MSDN Blogs Sign in | Join | Help

Premultiplied alpha

Remember when you first figured out Santa Claus wasn't real? The growing doubt, tempered by the fact that all your friends believed in him, and surely they can't ALL be wrong, then the gradual realization that everybody was in fact wrong...

Well, I've got another one for you: the way most people do alpha blending is bogus!

At a fundamental level, alpha has no special meaning at all. Graphics cards manipulate numeric values, but what they do with these values is entirely determined by what shader code you write and which render states you set. The hardware works with Vector4 data types. Because these often represent colors, it is natural to use the first three components for red, green, and blue. That leaves a spare component, called alpha, which can be used for absolutely anything we like.

Some people use alpha to store shininess, or ambient occlusion, or a collision material ID. In the MotoGP particle system I used it to pass a per-particle random number into my vertex shader physics. But most often, alpha is used to represent transparency. It is important to understand that this is just a convention, and there are several different ways it can be done.

 

Conventional Alpha Blending

The majority of programmers, programs, programming APIs, file formats, etc, define transparency as:

  • RGB specifies the color of the object
  • Alpha specifies how solid it is

In math:

blend(source, dest)  =  (source.rgb * source.a) + (dest.rgb * (1 - source.a))

In code:

    RenderState.SourceBlend = Blend.SourceAlpha; 
    RenderState.DestinationBlend = Blend.InverseSourceAlpha; 

In this world, RGB and alpha are independent. You can change one without affecting the other. Even when an object is fully transparent it still has the same RGB as if it was opaque. Thus 100% transparency can be represented by many different color values.

There isn't really a direct physical analogy for this. I guess it's similar to how a magic cloak of invisibility works in a fantasy universe, where I can be wearing the same red sweater as I am right now, and it remains red even though it currently happens to be invisible.

 

Premultiplied Alpha Blending

Here's a different way to think about transparency:

  • RGB specifies how much color the object contributes to the scene
  • Alpha specifies how much it obscures whatever is behind it

In math:

blend(source, dest)  =  source.rgb + (dest.rgb * (1 - source.a))

In code:

    RenderState.SourceBlend = Blend.One; 
    RenderState.DestinationBlend = Blend.InverseSourceAlpha; 

In this world, RGB and alpha are linked. To make an object transparent you must reduce both its RGB (to contribute less color) and also its alpha (to obscure less of whatever is behind it). Fully transparent objects no longer have any RGB color, so there is only one value that represents 100% transparency (RGB and alpha all zero).

This is more like how light behaves in the real world. What is the RGB of my car windscreen? None: it is transparent, so has no color. How about my sunglasses? These have a fractional alpha value (letting some light some through, while blocking some) and also contribute some RGB for that nice rose-tinted glow.

To use premultiplied alpha, in addition to setting the appropriate renderstates, you must also convert your source graphics into premultiplied format. Drawing a non premultiplied color with premultiplied blending will not give sensible results!

To convert a non premultiplied color into premultiplied format:

color.rgb *= color.a

(hence why this is called "premultiplied" format)

Look at the blend equations for conventional vs. premultiplied alpha. If you substitute this color format conversion into the premultiplied blend function, you get the conventional blend function, so either way produces the same end result. The difference is that premultiplied alpha applies the (source.rgb * source.a) computation as a preprocess rather than inside the blending hardware.

I will write more about how to convert graphics into premultiplied format in a later post.

 

Why premultiplied r0x0rz

Premultiplied alpha is better than conventional blending for several reasons:

  • It works properly when filtering alpha cutouts (see below)

  • It works properly when doing image composition (stay tuned for my next post)

  • It is a superset of both conventional and additive blending. If you set alpha to zero while RGB is non zero, you get an additive blend. This can be handy for particle systems that want to smoothly transition from additive glowing sparks to dark pieces of soot as the particles age.

  • It plays nice with DXT compression, which only supports transparent pixels with an RGB of zero.

 

Premultiplied alpha cutouts

Remember how filtering can produce ugly fringes around the edges of alpha cutouts? Not a problem when using premultiplied alpha! Revisiting the example from my previous post:

tree  =  (0, 255, 0, 255)

border  =  (0, 0, 0, 0)

background  =  (0, 0, 255)

filtered  =  (tree + border) / 2  =  (0, 128, 0, 128)

With conventional alpha blending, the result is darker than we wanted:

result  =  lerp(background, filtered.rgb, filtered.a)  =  (0, 64, 128)

But premultiplied blending produces the right answer:

result  =  filtered.rgb + (background * filtered.a)  =  (0, 128, 128)

This works because texture filtering and premultiplied blending are both linear transforms, and are therefore associative:

blend(filter(a, b),  c)  ==  filter(blend(a, c),  blend(b, c))

Published Friday, November 06, 2009 11:39 AM by ShawnHargreaves

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

Friday, November 06, 2009 5:42 PM by Tim R.

# re: Premultiplied alpha

Any chance we can get some images for comparison? All these verbose descriptions and maths are a bit dry to try to read without any eye candy!

Saturday, November 07, 2009 12:58 AM by Nick - Novaleaf

# re: Premultiplied alpha

can't wait for the next post already, i guess that this will help solving alpha blend issue on deferred rendering.

Saturday, November 07, 2009 12:59 AM by novaleaf

# re: Premultiplied alpha

great, great info "The Shawn".  me and my graphic guy are hoping that your next post helps solve our deferred rendering alpha problems.

You got us on the edge of our seats!  =D

Wednesday, November 18, 2009 2:17 PM by KriS

# re: Premultiplied alpha

You didn't mention one thing - using premultiplied alpha increases DXT5 compression artifacts (DXT5 texture alpha channel is compressed with greater fidelity than the RGB channels). So it's not so great for textures with smooth alpha gradients. You may find some description and comparison pictures here: http://kriscg.blogspot.com/2009/11/premultiplied-alpha.html.

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
 
Page view tracker