Alpha compositing

Started by
7 comments, last by Hodgman 13 years, 4 months ago
Is there any "smart" way to do alpha compositing that I don't know about? I'm writing a GUI for my game, and there are UI elements with other elements on top of them. For example, a button with some text on top of it. The button background and the button text are rendered separately (because the text might change). If I want to set the button's alpha, how would I go about ensuring that the button and the text on top of the button blend properly?

For example, say I had a red box sitting on top of a green box, on a white background:



At 25% opacity, this is what it should look like:



Obviously, setting the alpha of the two boxes separately won't work:



The only solution I can think of is to render the button and the text to an offscreen rendertarget (without alpha), then blend the rendertarget with the backbuffer. But that seems crazy solution to what should be a simple problem. Is there some other way to do this that I'm not aware of?
NextWar: The Quest for Earth available now for Windows Phone 7.
Advertisement
RTT isn't that crazy... :)

If we assume a black background instead of a white background, it's possible. You could render your whole GUI onto this black background, and then composite the final result over your actual background.

In the case of your squares, we could say they've got 100% alpha, which is then modified to be 25% alpha.
The blend mode you'd want is:
Source * ModAlpha + Dest * (1-OrigAlpha)
where:
OrigAlpha = 100%
ModAlpha = 100% * 25%

However, that blend mode is too complicated to be configured though the built in blend unit, so you'd have to implement some of it in a shader.

You could use a shader to pre-multiply your alpha into the colour output, like:
float alphaModifier = 0.25;float4 main(...){  float4 texSample = ...  texSample.rgb *= texSample.a * alphaModifier;  return texSample;}
And then use pre-multiplied-alpha blending:
Source * One + Dest * (1-SrcAlpha)
Cannot you just disable Ztest and draw them? If the GUI elements are 2D, it will work just fine.

Previously "Krohm"

Quote:Original post by Hodgman
RTT isn't that crazy... :)

If we assume a black background instead of a white background, it's possible. You could render your whole GUI onto this black background, and then composite the final result over your actual background.

In the case of your squares, we could say they've got 100% alpha, which is then modified to be 25% alpha.
The blend mode you'd want is:
Source * ModAlpha + Dest * (1-OrigAlpha)
where:
OrigAlpha = 100%
ModAlpha = 100% * 25%

However, that blend mode is too complicated to be configured though the built in blend unit, so you'd have to implement some of it in a shader.

You could use a shader to pre-multiply your alpha into the colour output, like:*** Source Snippet Removed ***And then use pre-multiplied-alpha blending:
Source * One + Dest * (1-SrcAlpha)


I was hoping for a slightly more general solution: one that would work regardless of what was in the background. It seems as if the only way to do it properly is to draw to a rendertarget first, but that seems unnecessarily wasteful (and complicated, performance-wise).

Quote:Original post by Krohm
Cannot you just disable Ztest and draw them? If the GUI elements are 2D, it will work just fine.


It won't work, because the blending won't be right.
NextWar: The Quest for Earth available now for Windows Phone 7.
Quote:It seems as if the only way to do it properly is to draw to a rendertarget first, but that seems unnecessarily wasteful (and complicated, performance-wise).
Using the blend mode above, you just need one RT for your entire GUI, which shouldn't be too complicated. On modern cards, performance isn't an issue for RTT, except for where you blend both RT's together (a small fraction of a ms).
If you want to save RAM, you could make this RT as big as your biggest GUI, and render each GUI into it (and blit to main screen) one at a time.
Can you do regular alpha blending, but render from front to back with z testing?

I.e. draw the red square first with blending, and then render the green square second. It will reject everything underneath the red square, while drawing the green square around the red. This means each element only gets blended once with the background.
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
@karwosts

> Can you do regular alpha blending, but render from front to back with z testing?

That would work if the goal was only to blend UI elements with the background. However, it's surely also necessary to blend UI elements with each other --- e.g. a font on top of a button will look pretty ugly without partial alpha around the glyph edges.
Quote:Original post by Hodgman
Quote:It seems as if the only way to do it properly is to draw to a rendertarget first, but that seems unnecessarily wasteful (and complicated, performance-wise).
Using the blend mode above, you just need one RT for your entire GUI, which shouldn't be too complicated. On modern cards, performance isn't an issue for RTT, except for where you blend both RT's together (a small fraction of a ms).
If you want to save RAM, you could make this RT as big as your biggest GUI, and render each GUI into it (and blit to main screen) one at a time.


Well, my target platform is Windows Phone 7, so resources are extremely constrained. Custom shaders are also unavailable (which limits my options somewhat). I was hoping initially for a solution which wouldn't involve render targets, but I guess there's not much choice.

Quote:Original post by karwosts
Can you do regular alpha blending, but render from front to back with z testing?

I.e. draw the red square first with blending, and then render the green square second. It will reject everything underneath the red square, while drawing the green square around the red. This means each element only gets blended once with the background.


That'll work for solid elements (like the boxes in my example) but it won't work with anything that uses textures with an alpha channel. A classic example would be text, which is usually done with a character map on a texture drawn to the screen using quads. Relying on Z won't work there.
NextWar: The Quest for Earth available now for Windows Phone 7.
Is it possible to simply not make composite objects translucent? ;)

This topic is closed to new replies.

Advertisement