WebGL: Why does transparent canvas show clearColor color component when alpha is 0?

webgl

Solution

WebGL by default requires your colors to use premultiplied alpha. 1,0,0,0 is an invalid color because rgb of (1,0,0) * alpha of (0) = 0,0,0 not 1,0,0 so it's an invalid color and the spec is undefined for invalid colors. The results will be different on different browsers.

You have a few options

Tell WebGL your colors are not premultiplied

gl = canvas.getContext("experimental-webgl", { premultipliedalpha: false });

Get rid of the alpha channel

gl = canvas.getContext("experimental-webgl", { alpha: false });

Premultiply your alpha

var r = 1;
var g = 0;
var b = 0;
var a = 0;
gl.clearColor(r * a, g * a, b * a, a);

similarly in your shaders either pass in premultiplied colors or premultiply at the end.

gl_FragColor = vec4(color.rgb * color.a, color.a);

Your blending settings have no effect. They only used when you call `gl.drawXXX`, they are not used when the canvas is composited with the background.

Problem

Here's a simple spike showing my problem: ``` <html> <head> <title>Clear Color</title> <style type="text/css"> #stage { background-color: rgba(127,127,127,1); } </style> </head> <body> <canvas id="stage" width="100", height="100"></canvas> <script type="text/javascript"> var options = { alpha: true, premultipliedAlpha: true }; var ctx = document.getElementById("stage").getContext("webgl", options); ctx.clearColor(1, 0, 0, 0); ctx.enable(ctx.BLEND); ctx.blendFuncSeparate( ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA, ctx.ONE, ctx.ONE_MINUS_SRC_ALPHA ); ctx.clear(ctx.COLOR_BUFFER_BIT); </script> </body> </html> ``` The blendFunc is this: (sR*sA) + (dR*(1-sA)) = rR (sG*sA) + (dG*(1-sA)) = rG (sB*sA) + (dB*(1-sA)) = rB (sA*1) + (dA*(1-sA)) = rA ...which translates to this (I think): (1*0) + (0.5*(1-0)) = 0.5 (0*0) + (0.5*(1-0)) = 0.5 (0*0) + (0.5*(1-0)) = 0.5 (0*1) + (1.0*(1-0)) = 1.0 Why am I seeing a light pink canvas instead of just the grey that the CSS declares? The pink is obviously coming from my clearColor, but why is it showing the red when the alpha component is 0?

Original source