Three.js: WebGL contextAttributes are ignored if you pass a context as a parameter

Created on 14 Aug 2019  路  4Comments  路  Source: mrdoob/three.js

Description of the problem

I've just spent like 5-6 hours trying to figure out why canvas.toDataURL() was constantly giving me a blank image, in other words: why preserveDrawingBuffer: true did not have any effect.

I was able to narrow down the problem to the three.js library, so I investigated the WebGLRenderer, and this is what I've found in the constructor:
_gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes );

This means, if you pass a context as a parameter, some of the context attributes will be ignored, including (but not limited to): preserveDrawingBuffer, antialias, premultipliedAlpha, and alpha just to mention a few important ones.

Now you might ask, why would one pass a WebGLRenderingContext to the WebGLRenderer's constructor. The answer is:
That is the recommended way to create a WebGL2 renderer, based on the docs !

This is a pretty huge problem, I think we should implement (and recommend) a better way to get a WebGL2 Renderer, or at least, put a huge WARNING to the related pages on the docs for now.

It's very misleading the way it is now, because I provide the necessary parameters, and they're simply ignored, not even a warning in the console appears, or whatsoever. Programmers can waste a lot of time figuring out why those parameters don't have any effect, just like I did.

Maybe we should put a console.warn above the _gl = _context || _canvas.getContext( 'webgl', contextAttributes ) || _canvas.getContext( 'experimental-webgl', contextAttributes ); line: if the context was provided, warn the users that the given attributes (that were passed along with the context) will be ignored, and they should give those parameters to the context itself upon creation.
Modifying those parameters on the go according to the given ones would be even better, but it seems it's not possible: link

I can create a PR with a warning like that, but we should discuss it first.

Three.js version
  • [x] r107
Browser
  • [x] All of them
  • [ ] Chrome
  • [ ] Firefox
  • [ ] Internet Explorer
OS
  • [x] All of them
  • [ ] Windows
  • [ ] macOS
  • [ ] Linux
  • [ ] Android
  • [ ] iOS
Documentation

Most helpful comment

I've just spent like 5-6 hours trying to figure out why canvas.toDataURL() was constantly giving me a blank image, in other words: why preserveDrawingBuffer: true did not have any effect.

FYI, setting preserveDrawingBuffer to true is not required to take a screenshot.

All 4 comments

This means, if you pass a context as a parameter, some of the context attributes will be ignored

The WebGL 2 examples demonstrate the intended workflow. The idea is to set the context parameters before you create WebGLRenderer.

https://github.com/mrdoob/three.js/blob/e622cc7890e86663011d12ec405847baa4068515/examples/webgl2_multisampled_renderbuffers.html#L104-L107

Instead of modifying the renderer, let's try to update the following guide with an additional hint first. Something like: _Since you are manually creating the WebGL 2 rendering context, you also have to pass in all necessary context attributes. It's not possible to pass these parameters when creating WebGLRenderer._

https://threejs.org/docs/#manual/en/introduction/How-to-use-WebGL2

I've just made a PR with this. I've rephrased this, though:

It's not possible to pass these parameters when creating WebGLRenderer

Because it is technically possible to pass these parameters, only they won't do anything. What do you think?

Sounds good :+1:

I've just spent like 5-6 hours trying to figure out why canvas.toDataURL() was constantly giving me a blank image, in other words: why preserveDrawingBuffer: true did not have any effect.

FYI, setting preserveDrawingBuffer to true is not required to take a screenshot.

Was this page helpful?
0 / 5 - 0 ratings