3
votes

I'm trying to get a simple effect to display using WebGL. Naturally, this means I'm using the fragment shader language defined in the GLSL ES 1.0 specification.

The code I am working with is largely copied from other sources. It sets up a square and uses the fragment and vertex shaders to determine the pixel colors. The following code will just display a white square.

gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);

However, if I change the alpha component to 1.0 then it will show a black square instead.

gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); // displays a black square

I'm assuming that the color that is output by the fragment shader must be combined with some previous color. How do I make sure that only the last color (regardless of its alpha value) is what is actually chosen as the color to be displayed?

Or perhaps I've got the order the wrong way around. Perhaps there is a later phase that is combining with the color from the fragment shader to produce the white color. In any case, I know that some kind of blending is going on because when I change the alpha value to 0.5 I get a grey square. I just want to know, where is the white color coming from? And how do I get rid of it?

As far as I can tell the problem is not to do with the blending function. The code is on GitHub here. Try it out in Google Chrome or Firefox.

3
@rockerest. Thanks for the extra tags.Sean Seefried

3 Answers

5
votes

The white color is not coming from any WebGL blending operations. It happens because canvas DOM elements are composited with the web page they reside in. Setting the background color of the canvas DOM element to black fixes the problem. This phenomenon has been written about here. However, the most definitive answer comes from the WebGL specification. The behaviour of compositing can be defined by setting various attributes of the WebGLContextAttributes object. Quoting from the specification:

The optional WebGLContextAttributes object may be used to change whether or not the buffers are defined. It can also be used to define whether the color buffer will include an alpha channel. If defined, the alpha channel is used by the HTML compositor to combine the color buffer with the rest of the page.

Thus, an alternative solution, that does not involve setting the background of the canvas to black, is to ask for the WebGL context with the following Javascript code

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

It would be helpful if you posted code, but it seems very much like you are blending your fragment color with a white background.

A possible culprit would be some WebGL initialization code that looks like:

    gl.clearColor(1.0, 1.0, 1.0, 1.0);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.enable(gl.BLEND);

which initializes the color buffer clear color to white and enables alpha blending.

So to get rid of your problem, just don't enable blending. In other words, lose the gl.enable(gl.BLEND); statement.

Update: Now that you've posted your code, it sounds like your problem is the opposite of what I was speculating. Assuming that you want the black background to show through according to the alpha that you set, you should replace your gl.disable(gl.BLEND) with

    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.enable(gl.BLEND);
1
votes

I know NOTHING about this topic (glsl, webgl, etc.), but you said alpha which makes me think that's an RGBA value. So a 0.0, 0.0, 0.0, 0.0 is black, with 0.0 alpha coverage. In other words, totally transparent.

0.0, 0.0, 0.0, 1.0 is black with 1.0 alpha coverage. In other words, totally opaque. It sounds like the output is 100% correct.

Let me clarify, just in case the above wasn't clear (it seemed confusing to me).

The last number is just affecting the transparency of the color, the first three numbers are affecting the Red, Green, and Blue respectively.

I'm not sure of their max/min values, but in web browsers (my area of knowledge), the colors go from 0 to 255. Where 0 is none of that color, and 255 is all of that color.

So in your case you are requesting a square with 0 red, 0 green, and 0 blue (which is just black). However, when you set the transparency (the alpha channel) to zero, it renders as white (or more likely - transparent, and whatever is behind it is white). When you set the alpha transparency to .5 it renders Black (like 0,0,0 should) but only half visible. When you set the alpha transparency to 1.0, it renders a fully opaque, black square.

Make sense?