Search code examples
javascripthtmlcanvaswebgltransparency

webgl - don't empty canvas on each frame


I was trying to recreate the effect achieved by this code in the 2d context:

// frame background "repaint"
ctx.fillStyle = 'rgba(0,0,0,.08)';
ctx.fillRect( 0, 0, w, h );

// draw rest of frame

which essentially adds a "trail". An example can be seen here: http://codepen.io/towc/pen/mJzOWJ

I ended up learning that in webgl you can have similar "source-over" transparency by using the following methods:

gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
gl.enable( gl.BLEND );

and yes, I'm not using any fancy shaders nor am I trying to achieve 3d semi-transparency, I just want a simple composition based on the alpha value of the source and the color values of the destination.

The problem with the above code is that each frame, it looks like whatever was in the canvas on the previous frame gets completely removed, so the semi-transparency can be seen in each frame, but not across frames, as in the case of the "trail" in the canvas.getContext('2d').

As a solution to the cross-frame semitransparency, I can always fall back to providing the current canvas frame as a texture and drawing it at the beginning of the new frame, as to have the blending act in the way I want it to.

But obviously this could all be avoided if there was a way to tell the canvas not to remove everything at each frame, which I only guess is the issue.

Here's what I've tried: https://jsfiddle.net/206Ltsgo/ After cross-frame semi-transparency, I should be able to get something like this: http://codepen.io/towc/pen/bNWyOq

The answer can include suggestions to libraries, but ultimately should be vanilla. If I made the wrong assumption about the issue, ideally the answer should state the actual issue first, and if any, provide a solution. If the only solution is actually to send a texture, it would be helpful to know if there are very fast/short/efficient ways of sending the canvas as the texture.


Solution

  • turns out the issue was effectively that on every frame, the drawingBuffer was cleared. This can be overwritten by adding an attribute when defining your gl, as this mdn page points out:

    var gl = canvas.getContext( 'webgl', { preserveDrawingBuffer: true } );