Jump to content


Render Target Alpha and me?


11 replies to this topic

#1 Alamaise

    New Member

  • Members
  • Pip
  • 2 posts

Posted 19 April 2006 - 09:38 AM

Hi,

I've been tinkering with a problem. I'm trying to pre-render a gui control into a texture. The control can (and will) have alpha components needed for when I will render it to the backbuffer in the end. So my texture has target alpha. Yet when I render it to the texture and then onto the screen, the alpha gets worked in twice and the colors become 'washed out'.

Is there a way to setup my render-2-texture that I get a pre-rendered version that I can render to screen that will look the same way as if I had rendered all components directly to screen?

I'm a bit lost :surrender:

Thanks!

#2 Goz

    Senior Member

  • Members
  • PipPipPipPip
  • 574 posts

Posted 19 April 2006 - 10:01 AM

Disable alpha blending when you write to the texture?

#3 Alamaise

    New Member

  • Members
  • Pip
  • 2 posts

Posted 19 April 2006 - 10:31 AM

Sorry, I can't do that as e.g. Fonts need alpha for the anti-aliasing, and some components of the controls may have alpha as well that needs to be layered over it... imagine a mac style glass button where you have a background with round corners, text in it and a foreground with lots of transparency that adds the glassy highlights. :)

#4 Wernaeh

    Senior Member

  • Members
  • PipPipPipPip
  • 368 posts

Posted 19 April 2006 - 11:16 AM

Hi there :)

Consider the equations for the resulting pixel color:
Rendering directly to screen yields

pcol_1 = initcol *alphafirst + newcol_1 * alphafirst_inv
pcol_2 = pcol_1 * alphasecond + newcol_2 * alphasecond_inv
pcol_3 = pcol_2 * alphathird + newcol_3 * alphathird_inv
....

i.e. an equation of the form
(((b * a1 + c * a1_inv) * a2 + d * a2_inv) * a3 + e * a3_inv) * ... + ....

What you now want, is to restructure this equation, so
that you instead get

bk_col * aavg + tex_col * aavg_inv

with bk_col equal to b in the prior equation.
Additionally, tex_col also needs to be of the same form as the first equation, since you also generate it by alpha composition.

This will not work out for several reasons.

The most prominent probably is that you need to mix in some sort of background color for the composition of the prerendered texture, which basically shows through all components.

Other reasons include that mathematically solving for the desired aavg parameter above probably yields an equation you cannot achieve without going all pixelshader :)

What keeps you from compositing your texture on the backbuffer, anyways ? :) Its usually not that much of a problem to render a few translucent quads these days. If it desperately needs to be rendered seperately, maybe force the lowest menu layer to be nontranslucent, and render to another buffer, and later on merge these.

Another option maybe would be to create the target alpha in another step, and have each texture carry a "resulting alpha" map, which are combined with a greater-than operation.

Cheers,
- Wernaeh

#5 Nils Pipenbrinck

    Senior Member

  • Members
  • PipPipPipPip
  • 597 posts

Posted 19 April 2006 - 04:56 PM

It's doable, and it's not even that difficult.

What you need to do is to use Porter Duff blending (google on this!).

In short:

What you need to do is to convert all the assets you use during rendering of your GUI rendertarget to premultiplied alpha, convert all colors/vertex colors you use to premultiplied alpha and compose your rendertarget using the Porter-Duff blendmode SRC_OVER_DEST.

You'll end up with a render-target that's premultiplied as well (thus - it looks horrible when you look at it.. Everything that's partly transparent is dark).

Now - during the final blit (combining your GUI-Rendertarget with the engine-image), pretend that the engine-image is fully opaque (it ought to be.. all pixels should have their final color). If you do so you can blend the image ontop (again using Porter-Duff SRC_OVER_DEST) and end up with a non premultiplied result.

This is btw, the reason this blending scheme has been invented (at Lucas Films btw). In the 80th it took very long to alpha-blend images together, and it was cheaper to buy two or more machines and split the compositing into several passes that could be done in parallel. A final blend-step then combined all partly blended images into one final, non-premultiplied image.

You surely don't need to machines to do the same thing.. You do it in two passes.

Btw, if you dig deeper into that stuff you'll find a *lot* of other iteresting blendmodes that you can use.. Delaying the final combine is just one use of it. It is much more flexible than our tried and trusted order dependent alpha-blend, but it's a bitch to work with if you have mixed premultiplied and ordinary images.

Nils

#6 Reedbeta

    DevMaster Staff

  • Administrators
  • 4979 posts
  • LocationBellevue, WA

Posted 19 April 2006 - 05:16 PM

Nils Pipenbrinck said:

it's a bitch to work with if you have mixed premultiplied and ordinary images.

Of course, you can convert ordinary images to premultiplied alpha extremely easily... :)
reedbeta.com - developer blog, OpenGL demos, and other projects

#7 Nils Pipenbrinck

    Senior Member

  • Members
  • PipPipPipPip
  • 597 posts

Posted 21 April 2006 - 10:36 AM

Reedbeta, yes, you can, but it starts to get ugly if you need the same image with alpha and without. Premultiplication is destructive.

anyways, by luck I found the original Porter-Duff paper.. Worth reading:

http://keithp.com/~k...p253-porter.pdf

#8 juhnu

    Valued Member

  • Members
  • PipPipPip
  • 292 posts

Posted 22 April 2006 - 10:55 AM

Wouldn't it work if you just did:

1. Render the GUI normally to a render target, in the same way you would render it directly to the backbuffer.
2. Blend the GUI-render target on the backbuffer using the following blend setup: SrcBlend = One and DestBlend = InvSrcAlpha.

#9 Reedbeta

    DevMaster Staff

  • Administrators
  • 4979 posts
  • LocationBellevue, WA

Posted 22 April 2006 - 05:31 PM

The problem is, what color do you clear the render target to? No matter what color you choose, some of that background will be blended into the GUI image, which is not really what you want.
reedbeta.com - developer blog, OpenGL demos, and other projects

#10 juhnu

    Valued Member

  • Members
  • PipPipPip
  • 292 posts

Posted 23 April 2006 - 10:33 AM

Reedbeta said:

The problem is, what color do you clear the render target to? No matter what color you choose, some of that background will be blended into the GUI image, which is not really what you want.

That's why the final blend is using premultiplied alpha (SrcBlend = One) and the background should be set to transparent black float4(0,0,0,0). This works because the blend is additive.

By the way, the same blending mode is usually used for particle effects as most of time particle textures are made so that particles on them fade to black - even when you dont want black color in the final rendered image.

However, Nils has a point that the blending mode used to render the GUI is not associative (InvSrcAlpha, SrcAlpha), and to fix that, one should use a different basic blending. However, I would argue that for this case, it could be ignored as it might look just as good or even better with the "wrong" order.

#11 geon

    Senior Member

  • Members
  • PipPipPipPip
  • 893 posts

Posted 23 April 2006 - 04:23 PM

I had exactly this problem when I played with 2D alpha blending. I guess you realize you need to compute the correct new alpha value of the combined textures. In my software alphablender, I used this formula:

(All values in range [0,1])
CombinedAlpha = 1-( (1-(SourceAlpha*Opacity)) * (1-DestinationAlpha) )

I'm not sure if this is appliable to hardware rendering without pixel shaders, though... I'm not experienced with that.

#12 juhnu

    Valued Member

  • Members
  • PipPipPip
  • 292 posts

Posted 24 April 2006 - 02:18 AM

a commonly used blending function is (SRC_OVER_DEST) which is not associative:

R = R1 (1 - A2) + R2 A2
G = G1 (1 - A2) + G2 A2
B = B1 (1 - A2) + B2 A2
A = A1 (1 - A2) + A2 A2

What Nils suggested is to use a following associative blending function instead:

R = R1 A1 (1 - A2) + R2 A2
G = G1 A1 (1 - A2) + G2 A2
B = B1 A1 (1 - A2) + B2 A2
A = A1 (1 - A2) + A2

..which can be simplified by using premultiplied alpha -textures.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users