I've been trying to create my own 2d renderer for my game (for learning purposes) and I'm trying to implement alpha compositing. The formula I'm using is very trivial, which is color = alpha * src + (1 - alpha) * dest.

Everything seemed to be going and looking well until I started comparing it to existing 2d canvas implementations. I've tested my canvas against OpenGL, the JS canvas, and a BufferedImage in Java, and they have all been getting slightly different results to the formula I use.

For example, let's say I have a background with a red value of 1 and shape with a red value of 0.49 and an alpha of 0.026. From plugging in the values to the formula, I got a red value of 251.6187 (multiplying the original result by 255), which can be rounded to 252. However, every canvas implementation I've used returns a red value of 251.

I'm keeping all my color values in a float between 0 and 1. However, I've tried experimenting with rounding it to increments of 255 and it still had no effect. For the js canvas implementation, I simply multiply the 0-1 by 255. (BufferedImage and OpenGl both accept a float from 0-1)

Here is a program to illustrate the issue: https://editor.p5js.org/SarahJ/sketches/VTzi0r5c7

I initially thought I needed to apply round, floor, or ceil function to my result, but while that helped this example, it caused problems for others.

Is this not the alpha compositing formula that most 2D canvas implementations use, or am I doing something wrong? Any advice is appreciated. Thanks!

  • \$\begingroup\$ Maybe they just use the floor instead of the round function since it should be cheaper to process. Nobody can tell if a color value is 251 or 252 just by looking at the displayed color. However, I am not sure if this is the reason. \$\endgroup\$
    – wychmaster
    Apr 21, 2020 at 10:59
  • \$\begingroup\$ @wychmaster That was my initial thought, but when I tried it even though it fixed the example problem above, the same problem occurred for other RGB values. \$\endgroup\$
    – Sarah
    Apr 21, 2020 at 11:14
  • \$\begingroup\$ For example, when I changed the 0.49 to 0.5 the js implementation returned 252 while mine returned 251. The cutoff for the standard implementations seems to be around 0.6 for some reason. Any ideas why this might be? \$\endgroup\$
    – Sarah
    Apr 21, 2020 at 11:17
  • 1
    \$\begingroup\$ Hard to tell without seeing the implementations. Huge maybe: Can be a result of gamma correction (en.wikipedia.org/wiki/Gamma_correction). In general, your formula is just linear interpolation and you are using it correctly. \$\endgroup\$
    – wychmaster
    Apr 21, 2020 at 11:37
  • \$\begingroup\$ @wychmaster You could be right... but I guess that means I can't really do anything about it. However, even when I change color space it still has the same result, and I'm not sure that the html5 canvas does it either. Anyway, I guess it's not a huge deal so I'll leave it for now, but I'll still be waiting for an answer just in case someone does find one. Thanks! :) \$\endgroup\$
    – Sarah
    Apr 21, 2020 at 12:16


You must log in to answer this question.

Browse other questions tagged .