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

Started by
16 comments, last by darenking 18 years, 7 months ago
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]
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
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
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?
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!
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.
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]
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);}
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?
Anyway thanks very much for that mike, you totally saved my life. Have rated you up.

This topic is closed to new replies.

Advertisement