|
| 1 | +Title: WebGL2 and Alpha |
| 2 | +Description: How alpha in WebGL is different than alpha in OpenGL |
| 3 | +TOC: WebGL2 and Alpha |
| 4 | + |
| 5 | + |
| 6 | +I've noticed some OpenGL developers having issues with how WebGL |
| 7 | +treats alpha in the backbuffer (ie, the canvas), so I thought it |
| 8 | +might be good to go over some of the differences between WebGL |
| 9 | +and OpenGL related to alpha. |
| 10 | + |
| 11 | +The biggest difference between OpenGL and WebGL is that OpenGL |
| 12 | +renders to a backbuffer that is not composited with anything, |
| 13 | +or effectively not composited with anything by the OS's window |
| 14 | +manager, so it doesn't matter what your alpha is. |
| 15 | + |
| 16 | +WebGL is composited by the browser with the web page and the |
| 17 | +default is to use pre-multiplied alpha the same as .png `<img>` |
| 18 | +tags with transparency and 2D canvas tags. |
| 19 | + |
| 20 | +WebGL has several ways to make this more like OpenGL. |
| 21 | + |
| 22 | +### #1) Tell WebGL you want it composited with non-premultiplied alpha |
| 23 | + |
| 24 | + gl = canvas.getContext("webgl2", { |
| 25 | + premultipliedAlpha: false // Ask for non-premultiplied alpha |
| 26 | + }); |
| 27 | + |
| 28 | +The default is true. |
| 29 | + |
| 30 | +Of course the result will still be composited over the page with whatever |
| 31 | +background color ends up being under the canvas (the canvas's background |
| 32 | +color, the canvas's container background color, the page's background |
| 33 | +color, the stuff behind the canvas if the canvas has a z-index > 0, etc....) |
| 34 | +in other words, the color CSS defines for that area of the webpage. |
| 35 | + |
| 36 | +A really good way to find if you have any alpha problems is to set the |
| 37 | +canvas's background to a bright color like red. You'll immediately see |
| 38 | +what is happening. |
| 39 | + |
| 40 | + <canvas style="background: red;"><canvas> |
| 41 | + |
| 42 | +You could also set it to black which will hide any alpha issues you have. |
| 43 | + |
| 44 | +### #2) Tell WebGL you don't want alpha in the backbuffer |
| 45 | + |
| 46 | + gl = canvas.getContext("webgl", { alpha: false }}; |
| 47 | + |
| 48 | +This will make it act more like OpenGL since the backbuffer will only have |
| 49 | +RGB. This is probably the best option because a good browser could see that |
| 50 | +you have no alpha and actually optimize the way WebGL is composited. Of course |
| 51 | +that also means it actually won't have alpha in the backbuffer so if you are |
| 52 | +using alpha in the backbuffer for some purpose that might not work for you. |
| 53 | +Few apps that I know of use alpha in the backbuffer. I think arguably this |
| 54 | +should have been the default. |
| 55 | + |
| 56 | +### #3) Clear alpha at the end of your rendering |
| 57 | + |
| 58 | + .. |
| 59 | + renderScene(); |
| 60 | + .. |
| 61 | + // Set the backbuffer's alpha to 1.0 by |
| 62 | + // Setting the clear color to 1 |
| 63 | + gl.clearColor(1, 1, 1, 1); |
| 64 | + |
| 65 | + // Telling WebGL to only affect the alpha channel |
| 66 | + gl.colorMask(false, false, false, true); |
| 67 | + |
| 68 | + // clear |
| 69 | + gl.clear(gl.COLOR_BUFFER_BIT); |
| 70 | + |
| 71 | +Clearing is generally very fast as there is a special case for it in most |
| 72 | +hardware. I did this in many of my first WebGL demos. If I was smart I'd switch to |
| 73 | +method #2 above. Maybe I'll do that right after I post this. It seems like |
| 74 | +most WebGL libraries should default to this method. Those few developers |
| 75 | +that are actually using alpha for compositing effects can ask for it. The |
| 76 | +rest will just get the best perf and the least surprises. |
| 77 | + |
| 78 | +### #4) Clear the alpha once then don't render to it anymore |
| 79 | + |
| 80 | + // At init time. Clear the back buffer. |
| 81 | + gl.clearColor(1,1,1,1); |
| 82 | + gl.clear(gl.COLOR_BUFFER_BIT); |
| 83 | + |
| 84 | + // Turn off rendering to alpha |
| 85 | + gl.colorMask(true, true, true, false); |
| 86 | + |
| 87 | +Of course if you are rendering to your own framebuffers you may need to turn |
| 88 | +rendering to alpha back on and then turn it off again when you switch to |
| 89 | +rendering to the canvas. |
| 90 | + |
| 91 | +### #5) Handling Images |
| 92 | + |
| 93 | +By default if you are loading images with alpha into WebGL, WebGL will |
| 94 | +provide the values as they are in the file with color values not |
| 95 | +premultiplied. This is generally what I'm used to for OpenGL programs |
| 96 | +because it's lossless whereas pre-multiplied is lossy. |
| 97 | + |
| 98 | + 1, 0.5, 0.5, 0 // RGBA |
| 99 | + |
| 100 | +Is a possible un-premultiplied value whereas pre-multiplied it's an |
| 101 | +impossible value because `a = 0` which means `r`, `g`, and `b` have |
| 102 | +to be zero. |
| 103 | + |
| 104 | +When loading an image you can have WebGL pre-multiply the alpha if you want. |
| 105 | +You do this by setting `UNPACK_PREMULTIPLY_ALPHA_WEBGL` to true like this |
| 106 | + |
| 107 | + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); |
| 108 | + |
| 109 | +The default is un-premultiplied. |
| 110 | + |
| 111 | +Be aware that most if not all Canvas 2D implementations work with |
| 112 | +pre-multiplied alpha. That means when you transfer them to WebGL and |
| 113 | +`UNPACK_PREMULTIPLY_ALPHA_WEBGL` is false WebGL will convert them |
| 114 | +back to un-premultipiled. |
| 115 | + |
| 116 | +### #6) Using a blending equation that works with pre-multiplied alpha. |
| 117 | + |
| 118 | +Almost all OpenGL apps I've writing or worked on use |
| 119 | + |
| 120 | + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); |
| 121 | + |
| 122 | +That works for non pre-multiplied alpha textures. |
| 123 | + |
| 124 | +If you actually want to work with pre-multiplied alpha textures then you |
| 125 | +probably want |
| 126 | + |
| 127 | + gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); |
| 128 | + |
| 129 | +Those are the methods I'm aware of. If you know of more please post them below. |
| 130 | + |
| 131 | + |
| 132 | + |
0 commit comments