# Thread: Transparency math, unexpected result!

1. ## Transparency math, unexpected result!

Hi all, I just found something interesting... so I'm trying to combine two colors and their alpha values to give me another value, with a standard "over" operation, like the in http://en.wikipedia.org/wiki/Alpha_compositing.

To make it happen, I use code like this:
Code :
```result.rgb = over.rgb * over.a + under.rgb * under.a * (1.0 - over.a);
result.a = 1.0 - (1.0 - over.a) * (1.0 - under.a)```

So, if I put the color (1.0, 1.0, 1.0, 0.5) over (0.0, 0.0, 0.0, 0.0), I would expect to get (1.0, 1.0, 1.0, 0.5) back, but running through the math, I get:

result.rgb = (1.0, 1.0, 1.0) * 0.5 + (0.0, 0.0, 0.0) * 0.0 * (1.0 - 0.5);
result.a = 1.0 - (1.0 - 0.5) * (1.0 - 0.0);
which gives me (0.5, 0.5, 0.5, 0.5).

If I lay a color over nothing, shouldn't I get the original color back? Shouldn't the result of this operation be (1.0, 1.0, 1.0, 0.5)?

Could someone please explain this to me? I have a feeling I'm missing something very basic in combining colors...

Thanks!

2. ## Re: Transparency math, unexpected result!

As you multiply incoming color by its alpha, here it is 0.5, so this result is expected.

3. ## Re: Transparency math, unexpected result!

Since you didn't seem to read it the first time, I'll just quote what I said in your other thread.

Originally Posted by me
The equation you quoted is correct if you are only looking at two objects being blended together. When you have layers upon layers, you have to composite them one at a time. In doing so, each layer's color gets its own alpha multiplied into itself (Ca * alpha_a). So the destination color already had its alpha factored in; there's no need to do it twice.

4. ## Re: Transparency math, unexpected result!

I actually did read it the first time, I just have a hard time wrapping my mind around this math... its very unintuitive to me. Odd that I can understand calculus but colors can get the best of me.

I read somewhere that if I discard the multiplying by the alpha, I have to do it beforehand, if I want correct blending. But they also said that when I do this, I lose the "order" of multiple layers. So I'm kind of nervous about taking anything out of the equation.

If I change this
Code :
`result.rgb = over.rgb * over.a + under.rgb * under.a * (1.0 - over.a);`
to this
Code :
`result.rgb = over.rgb + under.rgb * under.a * (1.0 - over.a);`
and I try (1, 1, 1, .5) with (1, 1, 1, .5), I get (1.25, 1.25, 1.25, .75), when I would expect (1, 1, 1, .75).

If I change it to
Code :
`result.rgb = over.rgb * over.a + under.rgb * (1.0 - over.a)`
and try (1, 1, 1, .5) with (0, 0, 0, 0), I get (.5, .5, .5, .5), when I would expect (1, 1, 1, .5).

Isn't there an equation that can handle all these cases?

5. ## Re: Transparency math, unexpected result!

You should use the mix() instead of this

result.rgb = over.rgb * over.a + under.rgb * under.a * (1.0 - over.a);

6. ## Re: Transparency math, unexpected result!

Yeah if fact you are simply confused because of the under.a term, remove it and it will be easier.

7. ## Re: Transparency math, unexpected result!

The glsl spec says that mix() is x*(1-a)+y*a; in my terms thats over.rgb*over.a + under.rgb*(1-over.a), so it's mine without the under.a term.

But wont this fail if I mix (1, 1, 1, .5) and (0, 0, 0, 0)? It would incorrectly give me (.5, .5, .5, .5).

8. ## Re: Transparency math, unexpected result!

But wont this fail if I mix (1, 1, 1, .5) and (0, 0, 0, 0)? It would incorrectly give me (.5, .5, .5, .5).
Two things:

1: If "under.a" was in the computation, you'd get the same thing. Which is part of the reason why you don't need it.

2: That is the correct value.

9. ## Re: Transparency math, unexpected result!

But it isnt the correct value, I get a gray out of this. I wanted a half-transparent white.

Anyway, I did a bit of number-crunching, and I came up with this formula:

overpower = over.a
underpower = under.a * (1 - over.a)
overcontribution = overpower / (overpower + underpower)
undercontribution = underpower / (overpower + underpower)
result.rgb = over.rgb * overcontribution + under.rgb * undercontribution;

Photoshop seems to agree with me, because it gave me the same results for (1, 1, 1, .5) over (1, 0, 0, .5), which was (1, .67, .67, .75)

10. ## Re: Transparency math, unexpected result!

But it isnt the correct value, I get a gray out of this. I wanted a half-transparent white.
There's no such thing as "half-transparent white". Colors don't come with a transparency value.

If you have a non-premultiplied RGBA vector of (1, 1, 1, 0.5), the actual color of this is (0.5, 0.5, 0.5). That is, this is what you would see.

Similarly, while your blend function for "(1, 1, 1, .5) over (1, 0, 0, .5)" gives you "(1, .67, .67, .75)" back, the actual color is (1, 0.5, 0.5). Which is what you get if you do a straight linear interpolation between the source and destination based on the source alpha.

The reason OpenGL doesn't support what you're trying to do in it's blending stage is because OpenGL is designed primarily for rendering colors. Not for rendering transparency. The way you normally deal with transparency is as follows.

First, you clear the screen. Then you render everything that is opaque. After that, you render all transparent objects in order from farthest from the camera to nearest.

Therefore, the destination color in a blending operation, the "under" as you keep calling it, will refer to either the background color (the one you cleared the screen to), an opaque color, or the composite between the background or opaque opaque colors and some number of previously-rendered transparent colors.

The destination alpha doesn't mean anything. It doesn't get factored into the blend equation. This is why a linear interpolation based on the source ("over") alpha works.

If the destination color is the background color, then it's effectively the same as if its opaque. There's nothing "behind" the background to see, so there's no value there to have blended with.

If the destination color is an opaque color, then the original alpha for this rendering was 1.0. So the "under.a" is 1.0, which doesn't affect the equation. Linear interpolation gets you a proper color.

If the destination was a composite of an opaque/background color and some number of layered colors, it still doesn't matter. Because the composite of all of these layers is still fully opaque, and therefore has an effective alpha of 1.0.

To put it another way, you don't blend two transparent objects together. You're always blending a transparent object with an opaque object.

Page 1 of 2 12 Last

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts
•