Jump to content
  • Advertisement
Sign in to follow this  
darenking

SOLVED..... C++ - how does alpha blending work?

This topic is 4677 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Although I'm using Allegro, I don't think this is really an Allegro question as what I need to know is the principle of how pixels are blended. I'm writing my own alpha blending function, as I need it to be more flexible than the standard Allegro functions. I can use getr32(), getg32(), getb32() and geta32() to get the red, green, blue and alpha values of a pixel in the source and destination bitmaps. I can then use colour = makeacol(red, green, blue, alpha) to make the new colour with an alpha value. Finally I can putpixel(destination, x, y, colour) to put the pixel. But how do I decide on the levels of each colour and the alpha level? Let's say the source pixel is red with 50% translucency... 255, 0, 0, 127 And let's say we want to place it on a pixel that is grey with a translucency value of 150 (out of 255, which I guess is about three-fifths solid)... 100, 100, 100, 150 What would the final values be? Do I just add the colours together for example? Or do I deduct colours? If I deduct colours, which from which? The lowest from the heighest? Do I have to use the alpha value to alter the colour of each channel? I should mention that what I am creating is another alpha sprite. I'm not drawing a sprite to a solid background. I'm creating a new alpha sprite from two other alpha sprites, and the new alpha sprite must be capable of being placed finally on a background. For example, I may be drawing a brown hair shape, like a wig, on top of a pink head shape. This means of course that both sprites, the hair and the wig, will have zero pixels around the outside of the image (transparant), 255 in the middle for the solid areas, and pixels in the range 1-254 along the rim, if you see what I mean, to create the anit-aliasing style effect. So I can't just dump one on top of the other using draw_sprite_alpha(). Any help appreciated! [Edited by - darenking on August 30, 2005 7:54:27 AM]

Share this post


Link to post
Share on other sites
Advertisement
All values must be converted to the range (0,1)

Ca = (Ra,Ba,Ga) color a (top image)
Cb = (Rb,Bb,Gb) color b (bottom inage)

Aa alpha a
Ab alpha b

Cc final color
Ac final alpha

Cc = Ca*Aa + Cb*(1-Aa)
Ac = Aa + Ab - Aa*Ab

edit: for the colors 255, 0, 0, 127 and 100, 100, 100, 150 the final color is 208, 58, 58, 201

Share this post


Link to post
Share on other sites
No, you can do this too if the values are in range [0,255]:

Cc = Ca*Aa/255 + Cb*(255-Aa)/255

Or if you're using integers, you can do this if you want rounding:

Cc = (Ca*Aa+128)/255 + (Cb*(255-Aa)+128)/255

The multiplication, addition with 128 and division can be replaced with a lookup from a table, but I don't know if that's worth it on modern CPUs.

Or

Cc = (Ca*Aa + Cb*(255-Aa) + 128)/255

Share this post


Link to post
Share on other sites
I'm a bit confused to be honest.

I start with my two pixels, the pixel at coords x and y in the from image, and the same pixel in the destination image:

pixFrom
pixTo

Do I keep them like this or do I have to extract the three colours and the alpha from each, eg:

redFrom = getr32(pixFrom);
greenFrom = getg32(pixFrom);
blueFrom = getb32(pixFrom);
alphaFrom = geta32(pixFrom);

redTo = getr32(pixTo);
greenTo = getg32(pixTo);
blueTo = getb32(pixTo);
alphaTo = geta32(pixTo);

Or, judging by your examples, I need the alpha colour and a mixture of the three colours?

Share this post


Link to post
Share on other sites
Quote:

Cc = Ca*Aa/255 + Cb*(255-Aa)/255
Cc = (Ca*Aa+128)/255 + (Cb*(255-Aa)+128)/255
Cc = (Ca*Aa + Cb*(255-Aa) + 128)/255


Also I'm confused as to why Ab isn't mentioned in these formulas. Or does Cb contain Ab?

Remember I want to blend both images together to create a new sprite rather than just draw sprite a onto a flat bitmap b, creating an alpha sprite rather than a flat bitmap!

Share this post


Link to post
Share on other sites
Quote:
Original post by darenking
Quote:

Cc = Ca*Aa/255 + Cb*(255-Aa)/255
Cc = (Ca*Aa+128)/255 + (Cb*(255-Aa)+128)/255
Cc = (Ca*Aa + Cb*(255-Aa) + 128)/255


Also I'm confused as to why Ab isn't mentioned in these formulas. Or does Cb contain Ab?


Ab isnt needed to find the new color. You will need it to find the new alpha tho.

Share this post


Link to post
Share on other sites
Thanks for that mike.

So, how do I find that mysterious final alpha value?

Also I still don't get how I can put these examples into my program, as you use the colour and the alpha, whereas I have a value that is made up of the three colours and the alpha, and four values 0-255 representing the three colours and the alpha all separate.

Any ideas? Anyone fancy chalking up an example? Remember I want to finish with a new alpha sprite rather than a flat image, I'm not drawing to a background here. I'm blending two alpha sprites together to form a new alpha sprite, that I can finally draw onto the screen buffer.

This is what I have value-wise:

pixFrom, pixTo // two ints consisting of RGBA which can be separated into...

redFrom = getr32(pixFrom);
greenFrom = getg32(pixFrom);
blueFrom = getb32(pixFrom);
alphaFrom = geta32(pixFrom);

redTo = getr32(pixTo);
greenTo = getg32(pixTo);
blueTo = getb32(pixTo);
alphaTo = geta32(pixTo);



[Edited by - darenking on August 28, 2005 5:22:51 AM]

Share this post


Link to post
Share on other sites
This code is untested.
struct intColor
{
int r,g,b,a;
};

struct realColor
{
float r,g,b,a;
};

realColor intColorToRealColor(intColor c)
{
realColor nc;
nc.r = ((float)c.r)/255.0f;
nc.g = ((float)c.g)/255.0f;
nc.b = ((float)c.b)/255.0f;
nc.a = ((float)c.a)/255.0f;
return nc;
}

inrColor realColorToIntColor(realColor c)
{
realColor nc;
nc.r = c.r*255;
nc.g = c.g*255;
nc.b = c.b*255;
nc.a = c.a*255;
return nc;
}

intColor combine(intColor top,intColor bottom)
{
// EDIT: The next five lines are not optimization and must be here.
if(bottom.a == 0){
return top;
}else if(top.a == 0){
return bottom;
}

realColor a = intColorToRealColor(top);
realColor b = intColorToRealColor(bottom);
realColor f;

f.r = a.r*a.a + b.r*(1.0f-a.a);
f.g = a.g*a.a + b.g*(1.0f-a.a);
f.b = a.b*a.a + b.b*(1.0f-a.a);
f.a = a.a + b.a - a.a*b.a;

return realColorToIntColor(f);
}

Share this post


Link to post
Share on other sites
Thanks for this Mike.

There's a couple typos I picked out, inrColor should be intColor, and I assume realColor nc should be intColor nc? Both in this function:


inrColor realColorToIntColor(realColor c)
{
realColor nc; // should this be intColor?
nc.r = c.r*255; // cast???
nc.g = c.g*255;
nc.b = c.b*255;
nc.a = c.a*255;
return nc;
}





If I make those changes I get a warning "converting to 'int' from 'float'". Shall I do a cast or something? Or does it signify a problem with the code?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!