Alpha in WebGL and Canvas
I've been learning WebGL and have been confused how alpha blending works. Coming from working with the 2D <canvas> API, the WebGL behavior was was surprising to me.
(This post uses some recent HTML5 features which won't show up properly in older browsers or IE. I know Chome and Firefox will show it correctly).
The Problem
The demo below uses WebGL to draw white, gray, and black triangles in a
range of alpha values, all with the standard gl.BlendFunc(gl.SRC_ALPHA,
gl.ONE_MINUS_SRC_ALPHA)
. The results are weird. For example, why does the
row of black triangles get lighter than the background as alpha
decreases? If you change the background to be almost-but-not-quite
white, why do the white triangles stop fading entirely?
For reference, here's a version done using the canvas API which behaves as expected and clearly shows the differences in alpha behavior between canvas and WebGL:
The Answer
As I learned from
Gregg Tavares,
the answer to the puzzle is that WebGL blends the alpha channel differently than
canvas does. Using the standard gl.BlendFunc(gl.SRC_ALPHA,
gl.ONE_MINUS_SRC_ALPHA)
, WebGL's blending equation for alpha is:
A = Asrc * Asrc + Adest * (1 - Asrc)
If you start with an opaque buffer and render a
semi-transparent polygon, the result is that the buffer is now
semi-transparent (A = .5 * .5 + 1 * (1 - .5) = .75
).
This transparency allows the white background of the page to show through and blend with the WebGL colors. Putting text behind the WebGL canvas makes this obvious:
Gregg details
several ways to address this, including using { alpha: false }
when
requesting the context: