How Shawn learned to stop worrying and love premultiplied alpha

How Shawn learned to stop worrying and love premultiplied alpha

  • Comments 17

I like to think I know what I'm doing with computer graphics, so I find it embarrassing that it took us four versions to get something as fundamental as alpha blending right.

To cut a long story short, I didn't properly understand alpha blending until way too recently :-)

(but in my defense, it seems like many other people don't understand it either)

To leave the long story long:

Graphics programming, especially for games, is an interesting mix of science, art, and Rube Goldberg contraption. Some things can be mathematically proven to have a single correct solution, so you'd be crazy to do them any other way. Other times we can achieve great results from ad-hoc hacks that only make sense for a specific game or piece of hardware.

When I started making games, the focus was very much on the hack side of things. Most projects began with being given a piece of hardware, and told to go off and make it do something cool. Few people had formal backgrounds in math or computer graphics.

Over time, the focus shifted toward properly understanding the theory behind what we were doing. Many projects began with being given a stack of SIGGRAPH papers, and told to go off and implement the techniques described therein. This often left those of us who grew up figuring things out by trial and error scrambling to relearn old tricks.

So how did I learn about alpha blending?

The first time I encountered the concept of blending colors was in college, where I wrote a game programming library called Allegro. Working with 8 bit palettized colors, this included a draw_trans_sprite() function which used a 64k lookup table to precompute every possible combination of two color values. This could achieve many varied effects just by changing what went into the table, but with only 256 colors to choose from, the quality of the results was, well, kinda dubious :-)

The first time I experienced proper hardware alpha blending was on the Nintendo 64, where we used a mixture of additive and interpolative blending, mostly for special effects. Textures were extremely small, usually just 4 bpp, and drawn by hand with Deluxe Paint. If we saw filtering or blending artifacts, we just asked the artist to change the offending texture.

The first time I ran into alpha blending problems was on Playstation II, where the artists used scanned photos as a source for creating 4 and 8 bpp palettized textures. Thanks to the unholy combination of filtering and interpolative alpha blending, we got ugly fringes around the edges of our tree billboards. I fixed this by using our equivalent of a custom content processor to automatically adjust the RGB of transparent palette entries, changing them to match the average color of the texture as a whole. Problem solved (or so I thought...)

The second time I ran into alpha blending problems was when we moved from Playstation II to the original Xbox, and switched from palettized textures to the more efficient DXT compression. DXT1 only supports transparent pixels where the RGB is zero, so my automatic fixup was no longer possible and the black fringes returned. I 'fixed' this by switching to DXT5 format wherever possible, plus using alpha test to skip drawing the problematic borders of textures for which DXT5 would use too much memory. This was a delicate balancing act. If the alpha test threshold was too high, the trees appeared jagged and hard edged, but it was too low, they had black borders. Somewhere in between, both problems still existed, but neither was too obvious. Problem solved? (kinda, but it made me feel dirty...)

The third time I ran into alpha blending problems was when I optimized particle rendering by drawing into a lower resolution rendertarget. Rendertarget composition is fundamentally impossible when using interpolative alpha, but I didn't know this at the time. So I sat down with pen and paper, did some algebra, and figured out the blend math necessary to get the result I wanted. It turns out that I independently reinvented premultiplied blending, but I failed to generalize this or realize how useful it could be for other things!

A few years later, I read Tom Forsyth's excellent article about premultiplied blending. "Aha!" quoth I. "So that's what that crazy thing I used for the particles is called. And wow, it seems pretty handy for other stuff too." Then I promptly forgot all about it.

A few more years later, I left Climax, left England, moved to Seattle, joined Microsoft, and started working on XNA. Having forgotten Tom's article, it never occurred to me (or I guess to anyone else here) that this might be something worth including in our API.

Shortly after we shipped XNA v1, I saw the first "wtf is up with these crazy borders around my sprite?" question on our forums. In the middle of typing up a lengthy "here's the laundry list of hacks I used to work around this problem in MotoGP" reply, I remembered, "wait, didn't Tom know a better way to fix this?"

After several years of getting this same question, pointing people toward Tom's article, and watching the ensuing confusion because it was too hard to do this with our API, we decided it was time to fix this mistake once and for all.

Enter Game Studio 4.0.

And they all lived happily ever after.

(touch wood)

Makes me wonder what else is out there that I don't know but should?

  • It's great to finally see you join the club! Thank you!

    Some more things:

    - matrices for animation keyframes? Volume collapse!

    - matrices multiply from the left, quaternions from the right? Wtf?

    - no procedural audio? (Wait, you're fixing this, too in 4! Yay!)

    - left-handed triangle culling, right-handed coordinate system? (I mean, really?)

    Still time for 4.0 release :-)

  • > Texture processor:

    > - Why is color key on the default?

    > - Why is mip maps off the default?

    Because these are the best defaults for the largest number of developers (and especially for beginner developers who are less likely to understand these options or know how to change them).

    When we look at what people use textures for, significantly more than half are used as sprites in a 2D scene, often with non-pow-2 textures, where mipmaps are both unnecessary and would not even work on much hardware. For these people, no mips is a better default.

    Sure, people making 3D games will want mips, but a) this is less common, b) 3D developers are typically more experienced than those working in 2D, so are more able to change away from the default, and c) many 3D developers build their textures indirectly via ModelProcessor, rather than adding them directly to the content project, and in that case mipmaps on is indeed the default.

    Likewise, color key on is a good default for the many beginner developers who do not understand alpha channels and do not have a paint program that knows how to create them. The more experienced folks who have Photoshop, know how to use it, and want to use magenta in their textures, are more able to change this default than the beginner who is using Microsoft Paint and does not yet know what an alpha channel even is :-)

Page 2 of 2 (17 items) 12
Leave a Comment
  • Please add 2 and 4 and type the answer here:
  • Post