3

Is RenderingContext.drawElements correct when it clears the screen before it draws?

Consider these screenshots that show a step across a call to drawElements with the object already drawn being erased.

enter image description here

enter image description here

orb
  • 1,263
  • 1
  • 10
  • 16

1 Answers1

4

WebGL effectively clears the screen after the page has been composited. When you're stepping through stuff one line at a time it's going to be composited every time you stop.

If you don't want it to be cleared ask for preserveDrawingBuffer: true when you create the WebGL context as in

gl = someCanvas.getContext("webgl", { preserveDrawingBuffer: true });

As for why, from the spec

While it is sometimes desirable to preserve the drawing buffer, it can cause significant performance loss on some platforms. Whenever possible this flag should remain false and other techniques used. Techniques like synchronous drawing buffer access (e.g., calling readPixels or toDataURL in the same function that renders to the drawing buffer) can be used to get the contents of the drawing buffer. If the author needs to render to the same drawing buffer over a series of calls, a Framebuffer Object can be used.

Implementations may optimize away the required implicit clear operation of the Drawing Buffer as long as a guarantee can be made that the author cannot gain access to buffer contents from another process. For instance, if the author performs an explicit clear then the implicit clear is not needed.

The TL;DR version is preserveDrawingBuffer: false (the default) allows WebGL to swap buffers when compositing (that doesn't mean it will swap buffers but it can if it chooses to). preserveDrawingBuffer: true means it can't swap buffers, it must copy buffers. Copying is much slower than swapping.

Community
  • 1
  • 1
gman
  • 100,619
  • 31
  • 269
  • 393
  • Thanks for the guidance. I am trying to find this bool field so I can set it. it is at least not readily available on the RenderingContext or CanvasElement through ctrl-space. Digging deeper . . . – orb Jan 07 '15 at 15:06
  • 1
    Like it says in the answer, it's something you pass in to `getContext` when you create the `WebGLRenderingContext`. It's not something you can set later. – gman Jan 07 '15 at 16:59
  • @gman this answer was acknowledged, but I'm afraid I found a similar issue. The change you suggest only works when the scenery is a still (not animated). When it is, {preserveDrawingBuffer} will mess up the animation, not clearing the frame. I also found the gl.drawElements() to clear the background, while gl.drawArrays does not. I discovered that when I tried to put a background skybox behind your blockguy animation. That does not work, while the skybox is correctly displayed behind your light examples.. rotating F is drawn with gl.drawArrays, not twgl.drawObjectList (using gl.DrawElements) – Goodies Dec 28 '22 at 01:49
  • What happens if you would modify the reflecting skycube example shown on [this page](https://webgl2fundamentals.org/webgl/lessons/webgl-skybox.html) to contain some object using twgl.drawObjectList() and Element records, instead of the reflecting cube using gl.drawArrays() ? See also: https://arcanepython.github.io/ts/ some scenes show the skybox (tex3d, mixed texture, lights) and some scenes won't show the skybox (objectlist/BlockGuy, manytextures). The skybox is drawn first.. and the scene seems to clear the background. – Goodies Dec 28 '22 at 02:27
  • It's best practice to clear things yourself by calling `gl.clear` than to rely on WebGL's implicit clearing. – gman Dec 28 '22 at 03:03