PDA

View Full Version : AlphaBlend Formula/Algorithm



fabiano.salles
24-09-2008, 06:30 PM
Hello, guys!

I'm using VCL's TBitmap with PixelFormat = pf32bit and using the 4st of the pixel byte as my alpha channel. Instead of using the TRGBQuad record of delphi, I'm using the following datatypes:
type
PRGB32 = ^TRGB32;
TRGB32 = packed record
B, G, R, A : byte;
end;

Ok. It woks just fine and I can load and save bitmaps with a valid alpha channel.
Now I'm trying to blend pixels using the alpha information, but the formula I'm usiging is producing a strange result. Could anyone, please, tell me a valid formula to blend pixels using alpha channel or say what I'm doing wrong? This is what my code looks like:

procedure TfrmCGScreen.DrawScene;
var
x, y, m : integer;
p : PRGB32;
begin

//Just creating a background pattern...
for x:=0 to fBuffer.Width-1 do
for y:=0 to fBuffer.Height-1 do
with fBufferFisrtLine[Y*fBufferLineLength+X] do
begin
B := 0;
R := 0;
A := 0;
m := Tag div fBuffer.Height;
case m of
0 : B := ((x or y) + Tag) mod 255;
1 : G := ((x and y) + Tag) mod 255;
2 : R := ((x or y) + Tag) mod 255;
else
begin
G := ((x xor y) + Tag) mod 255;
tag := 0;
end;
end;
end;

//now I'm trying to blend the "fBlendImage" with the image in my backffuer
for y:=0 to fBlendImage.Height-1 do
begin
p := fBlendImage.ScanLine[y];
for x:= 0 to fBlendImage.Width -1 do
begin
with fBufferFisrtLine[Y*fBufferLineLength+ (X + (tag mod 600))] do
begin
B := B + p.B * p.A div 255;
G := G + p.G * p.A div 255;
R := R + p.R * p.A div 255;
end;
Inc(p);
end;
end;
Tag := Tag+1;
end;

Thanks a lot!

chronozphere
24-09-2008, 06:44 PM
Let's say B is the background pixel and S is the sourcepixel and D is the destenation pixel.

I would try this:


D.R := B.R + (S.R - B.R)*(S.A/255);
D.G := B.G + (S.R - B.G)*(S.A/255);
D.B := B.B + (S.R - B.B)*(S.A/255);


It's just weighted interpolation. :)
I've not tested this. Just made it up.

Hope this helps.... ;)

fabiano.salles
24-09-2008, 10:03 PM
Hey man, thanks for the fast reply!

Your interpolation works only for the 100% black pixels on the alpha channel (A=255). Changing it for the code below, it works for the shades of gray too.

D.R := B.R + (S.R - B.R) * S.A div 255;
D.G := B.G + (S.R - B.G) * S.A div 255;
D.B := B.B + (S.R - B.B) * S.A div 255;

chronozphere
25-09-2008, 06:30 AM
Hmm.. ofcourse. Using / turns the result into a float, and the components of D are bytes. :)

Does your sollution with DIV really work. DIV's result can only be an integer. :?
I assume that your alpha value is a byte (0-255). So dividing it by 255, will give you a result inside the 0..1 range. If you use DIV, i assume all results in this range will be rounded to zero.

I think this will be more accurate:



//Include the math unit to use "Floor"
D.R := Floor(B.R + (S.R - B.R)*(S.A/255));
D.G := Floor(B.G + (S.R - B.G)*(S.A/255));
D.B := Floor(B.B + (S.R - B.B)*(S.A/255));


Edit: I noticed you removed the brackets around "S.A div 255". I guess that'll make the difference. But could you try my snippet? I wonder wether it works.

User137
25-09-2008, 12:11 PM
D.R := B.R + (S.R - B.R) * S.A div 255;
D.G := B.G + (S.R - B.G) * S.A div 255;
D.B := B.B + (S.R - B.B) * S.A div 255;

This code definitely should work. Division is last operation there so there will not be any math errors. Using function to round float to int makes it just slower.

chronozphere
25-09-2008, 01:24 PM
Ok, thanks. Good to know. :)

fabiano.salles
30-09-2008, 11:41 PM
User137 is rigth, chronozphere.

As you ask me, I tested your other suggestion and it worked too (but the speed difference is very big between the two approaches).
If you wanna see the code, you can download it here:
http://www.fabianosalles.eti.br/blog/delphi/files/test/AlphaBlendTeste01.rar

ps: use the '1' and '2' keys to switch between the calculations. Here in my machine it run with ~400fps, but as I'm using only GDI and VCL, the runtime speed may vary too much.

Thanks :D

chronozphere
03-10-2008, 06:25 AM
Your demo looks really cool. I like the animated background. :)

Switching between the modes doesn't make a real difference for me. The FPSses are varying between 380 and 420 (for both modes). It might be, because things like rounding and floating-point divisions are alot faster on my CPU than on yours. :?

What CPU do you have and what kind of speed difference do you see in your FPSses? I have an AMD 2X 64 5400+.

Thanks. :)

fabiano.salles
03-10-2008, 11:54 AM
I run this last code only on the work computer and here I have a variation beteewn 490 and 520 fps, but when I swicth the "blend mode" ( :lol: ), it drops to ~300fps.