C++ Additive Blending Algorithm 2d Game

by RNewell122   Last Updated October 19, 2019 14:13 PM

I was wondering if anyone could shed any light on whats going wrong with my additive blending here, I think I'm nearly there, currently my outcome is black squares. I have tried using both the formula's on this website here https://love2d.org/wiki/BlendMode_Formulas to try and get my desired outcome and it doesn't seem to be working.

This is the equation I have in my notes and what I have found online. Final.Red = Bitmap.Red + Viewport.Red Similar for green and blue, RGB range is [0-1] or [0-255]

The colors I am using are 255 RGBA format.

void SpritePlotterForm::DrawSpriteAdd( int X, int Y, Bitmap^ SrcBitmap )
{

    int FinalViewPortRed;
    int FinalViewPortGreen;
    int FinalViewPortBlue;
    int FinalViewPortAlpha;
    for (int x = 0; x < SrcBitmap->Width; x++)
    {
        for (int y = 0; y < SrcBitmap->Height; y++)
        {
          if (SrcBitmap->GetPixel(x, y).A >= 0)
          {
                // resets to avoid corruptionj of image
                FinalViewPortRed = (SrcBitmap->GetPixel(x, y).R + GetViewportPixel(x+ X, y + Y).R)/255;
                FinalViewPortGreen = (SrcBitmap->GetPixel(x, y).G + GetViewportPixel(x + X, y + Y).G) / 255;
                FinalViewPortBlue = (SrcBitmap->GetPixel(x, y).B + GetViewportPixel(x + X, y + Y).B) / 255;
                Color ResultColour = Color::FromArgb(FinalViewPortRed, FinalViewPortGreen, FinalViewPortBlue);
                SetViewportPixel(X + x, Y + y, ResultColour);

          }
       }
    }

}

I think the error is to do with how I am handling my alpha values, but I have tried multiple algorithms and either, end up darkening the image, creating a whole black square, or a whole transparent square, or worst is it gets an out of bounds issue.

Image to be blended The Image file to be additively blended

the result I get from this algorithm (run twice, those are two seperate flames there)

The result

Desired outcome

enter image description here



Answers 2


If you calculate the final result as final.red = bitmap.red + viewport.red and divide by 255, then you are simply averaging them out, without taking alpha into account. The way I learned to calculate transparency is a formula that is also present in the top of the page you linked:

res.r = dst.r * (1 - src.a) + src.r * src.a
res.g = dst.g * (1 -src.a) + src.g * src.a
res.b = dst.b * (1 - src.a) + src.b * src.a

So that would be along the lines of

            // resets to avoid corruptionj of image
            FinalViewPortRed = (SrcBitmap->GetPixel(x, y).R * SrcBitmap->GetPixel(x, y).A + GetViewportPixel(x+ X, y + Y).R) * (1-SrcBitmap->GetPixel(x, y).A);
            FinalViewPortGreen = (SrcBitmap->GetPixel(x, y).G * SrcBitmap->GetPixel(x, y).A  + GetViewportPixel(x + X, y + Y).G)  * (1- SrcBitmap->GetPixel(x, y).A) ;
            FinalViewPortBlue = (SrcBitmap->GetPixel(x, y).B  * SrcBitmap->GetPixel(x, y).A + GetViewportPixel(x + X, y + Y).B)  * (1-SrcBitmap->GetPixel(x, y).A) ;

It is then also important to adjust the new alpha value of the resulting color! (Since 2 transparent objects over each other will result in a color that is less transparent)!

res.a = dst.a * (1 - src.a) + src.a

Again, this woud look probably someting ike this in your code:

            FinalViewPortAlpha = (SrcBitmap->GetPixel(x, y).A + GetViewportPixel(x + X, y + Y).A * (1-SrcBitmap->GetPixel(x, y).A) ;

EDIT: Assuming you wanted or needed to use the formula you specified in your question, that seems to be a so called "premultiplied alpha" calculation. Your link has a brief description, but doesn't really say how alpha even comes into play.
Wikipedia has a better description. I think the most useful thing for you is the description (i manually put the a in, standing for alpha, the wiki has a concrete number, but we want to be more general)

If an alpha channel is used in an image, it is common to also multiply the color by the alpha value, to save on additional multiplications during compositing. This is usually referred to as premultiplied alpha.

and also

...if this pixel uses premultiplied alpha, all of the RGB values (0, x, 0) are multiplied by a and then the alpha is appended to the end to yield (0, x * a , 0, a ).

I haven't used this formula, but it seems you simply multiply alpha ( => [0,1]) to all of it's colors (so src.r * src.a, scr.g * scr.a....) and then add up the colors in the end after doing so.

PS: Checking SrcBitmap->GetPixel(x, y).A >= 0 seems kind of pointless here, since alpha is [0,1], so that would need to always be true

Throzen
Throzen
January 27, 2016 21:44 PM

its showing error 'value of'859' is not valid for 'red'. 'red' should be greater than or equal to 0 and less than or equal to 255.'

basil mon
basil mon
October 19, 2019 13:26 PM

Related Questions


Updated July 14, 2015 15:05 PM

Updated August 26, 2019 22:13 PM

Updated April 08, 2015 18:05 PM

Updated January 06, 2017 08:05 AM

Updated November 14, 2018 23:13 PM