0
\$\begingroup\$

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

\$\endgroup\$
2
\$\begingroup\$

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

\$\endgroup\$
  • \$\begingroup\$ sorry I've just tested this out and ive got an out of bounds error where im returning -255 in one of the final alpha, can you help me out a bit again ? @Throzen \$\endgroup\$ – RNewell122 Jan 27 '16 at 21:53
  • \$\begingroup\$ would using abs ? fix this ? \$\endgroup\$ – RNewell122 Jan 27 '16 at 22:07
  • 1
    \$\begingroup\$ hmm, are you using [0, 255] for alpha ? I believe that alpha definitely needs to be between 0 and 1, otherwise the "(1 - src.a)" wouldn't even make sense, since it's basically saying "we want this much of a percentage of the source". So first make sure that alpha is definitely [0, 1]. \$\endgroup\$ – Throzen Jan 27 '16 at 22:09
  • \$\begingroup\$ No you are correct the alpha should be 0.0 - 1.0 \$\endgroup\$ – RNewell122 Jan 27 '16 at 22:11
  • 1
    \$\begingroup\$ comment became too long, added another possibility to why your formula might be Final.Red = Bitmap.Red + Viewport.Red in my answer, just keep in mind I have never used this formula myself, so I cannot speak from experience, but the wiki is not bad describing premultiplied vs non-premultiplied´. And again, make sure to also adjust the resulting alpha value! \$\endgroup\$ – Throzen Jan 27 '16 at 22:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.