Sign in to follow this  
Hachaso

Alpha blending help

Recommended Posts

Hi! I need some help with alpha blending. What I have done, is to write 2 different functions that are supposed to return the same value. The problem is that something is different and I can't seem to figure out what. I have done it by hand to see that the calculation is correct and still nothing. Please tell me if I'm on the right track. Is that the way to do alpha blending? And also what is the difference between the two functions? Here's the code: Alpha is mapped to a value between 0 - 32. If I understand correct, alpha originally is a float containing a value between 0.0 - 1.0. So now I have mapped alpha to an unsigned char value between 0 - 32. unsigned short rgb565Blender1(unsigned short ColorA, unsigned short ColorB, unsigned char Alpha) { unsigned short res = 0; unsigned short ColorAred = 0; unsigned short ColorAgreen = 0; unsigned short ColorAblue = 0; unsigned short ColorBred = 0; unsigned short ColorBgreen = 0; unsigned short ColorBblue = 0; unsigned short resR = 0; unsigned short resG = 0; unsigned short resB = 0; ColorAred = ColorA & (0x1f << 11); ColorBred = ColorB & (0x1f << 11); ColorAgreen = ColorA & (0x3f << 5); ColorBgreen = ColorB & (0x3f << 5); ColorAblue = ColorA & 0x1f; ColorBblue = ColorB & 0x1f; resR = ((Alpha*(ColorAred - ColorBred)) >> 5) + ColorBred; resG = ((Alpha*(ColorAgreen - ColorBgreen)) >> 5) + ColorBgreen; resB = ((Alpha*(ColorAblue - ColorBblue)) >> 5) + ColorBblue; res = resR | resG | resB; return res; } Next function here with some minor differences. unsigned short rgb565Blender2(unsigned short ColorA , unsigned short ColorB , unsigned char Alpha) { unsigned short res = 0; unsigned short ColorAred = 0; unsigned short ColorAgreen = 0; unsigned short ColorAblue = 0; unsigned short ColorBred = 0; unsigned short ColorBgreen = 0; unsigned short ColorBblue = 0; unsigned short resR = 0; unsigned short resG = 0; unsigned short resB = 0; ColorAred = (ColorA >> 11) & 0x1f; ColorBred = (ColorB >> 11) & 0x1f; ColorAgreen = (ColorA >> 5) & 0x3f; ColorBgreen = (ColorB >> 5) & 0x3f; ColorAblue = ColorA & 0x1f; ColorBblue = ColorB & 0x1f; resR = (Alpha*(ColorAred - ColorBred) >> 5) + ColorBred; resG = (Alpha*(ColorAgreen - ColorBgreen) >> 5) + ColorBgreen; resB = (Alpha*(ColorAblue - ColorBblue) >> 5) + ColorBblue; resG = resG << 5; resR = resR << 11; res = resB | resG | resR; return res; } Thanks for the help!

Share this post


Link to post
Share on other sites

resG = resG << 5;
resR = resR << 11;


That seems to be missing from the first function. Generally you use an API's alpha blending instead of writing your own. As for if your method is correct, I think alpha blending is normally just topColor*alpha+bottomColor*(100%-alpha).

Share this post


Link to post
Share on other sites
resG = resG << 5;
resR = resR << 11;

I have done this cause the last function shifts all bits to the right.
When I add the differente colors together I want them in there right place.

Isn't the blending formula like this?

BlendedColor = Alpha * src + (1 - Alpha)* dest

I'm doing this to better understand alpha blending.

Share this post


Link to post
Share on other sites
To understand alpha blending, first turn everything into a double from 0.0 to 1.0. Playing around with bits makes it faster and more optimized -- but you want to first understand the concepts of alpha blending.

Here is the canonical alpha blending equation for linear unshaped colour:

A_X : alpha of X
C_X : colour of X
A_T : alpha of top
A_B : alpha of bottom
A_R : alpha of result

All 3 colour channels are treated exactly the same way, so you only need one equation for all 3. :)

A_R = A_T + A_B*(1-A_T)
C_R = [C_T*A_T + C_B*A_B*(1-A_T)]/A_R


Now there are special cases. If the A_B is 1 (the bottom is opaque), the above equations reduce to:

A_R = 1
C_R = C_T*A_T + C_B*(1-A_T)


which is much nicer, don't you think?

Finally, there is what is known as "shaped" or "pre multiplied" colour. In non-shaped colour, transparent white and transparent black are different -- in shaped colour, they bitwise identical.

The alpha channel for shaped pixels is identical. The colour channel is different.

S_X is the "shaped colour channel of X".

S_X = C_X * A_X
the above is why it is known as "pre-multiplied" colour. To convert back:
C_X = S_X/A_X
(if alpha is 0, the above is undefined -- quite rightly. Completely transparent objects don't have a colour.)

With shaped colour, alpha aware compositing gets easier:
A_R = A_T + A_B*(1-A_T)
S_R = S_T + S_B*(1-A_T)


Notice how much simpler the shaped equations are than the unshaped equations.

...

Back on topic. To understand how alpha blending works, take your parameters, turn them into 0.0 to 1.0 doubles, do the above equations, then convert them to the output format.

This isn't efficient. To make it efficient, people emulate the floating-point operations using fixed-point math, operating directly on the integers used to represent alpha and colour channels. However, that isn't really part of alpha compositing -- it is a different subject entirely. First understand how compositing works, then optimize it. :)

Share this post


Link to post
Share on other sites
Thanks for the explanation.

I guess working with double values instead of mapped alpha to an unsigned char would be better. But still I have one question.

If a color is of double type, this means that the value can be a decimal one like, 45.657 for instance.
How do I extract the Red, Green and Blue color from this?

For instance:

colorAred = uiA & 0xF800;

This line puts zero's on evertying exept the 5 most significant bits, containing the color RED. This is the part where you lost me if I should work with double values.

Thanks!

Share this post


Link to post
Share on other sites
No. I'm not saying you should change your entire engine to working with doubles.

I'm talking about figuring out how to composit one value.

You start with Red, Green, Blue and Alpha for each pixel (both the top and the bottom). You do what you have to do in order to turn them into doubles from 0.0 to 1.0. Then you use the above math.

RG and B are all treated the same way -- so I simply gave instructions on how to deal with any colour channel. Alpha is treated differently.

There are two problems here. The first problem is "how do I composit". The second problem is "what is the format of my pixel data". The are seperate problems. Trying to solve both of them at the same time will simply confuse you.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this