question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Three.JS WebGLRenderer fails to create when canvas is not initialized.

See original GitHub issue

Describe the bug I’m using Expo React-Native with Three.JS, and just recently noticed a new bug that happens when I’m initializing the Three.JS renderer. TypeError: null is not an object (evaluating 'gl.canvas.width').

Same as mentioned in this thread.

I’ve pinpointed the source of the issue to be due to this change https://github.com/mrdoob/three.js/commit/f5c6b1c944a2dba2c7abb9fb780719a8fbe46ab0, specifically

The changing of the following lines in its initialization from

	const currentScissor = new Vector4();
 	const currentViewport = new Vector4();

to

 	const currentScissor = new Vector4( 0, 0, gl.canvas.width, gl.canvas.height );
 	const currentViewport = new Vector4( 0, 0, gl.canvas.width, gl.canvas.height );

I’ve tested by replacing these lines with the original ones (the Vector4 without parameters) and this issue is gone.

I’m filing this issue to ask if it will be ok if I create a pull request to change these lines to be

 	const currentScissor = gl.canvas ? new Vector4( 0, 0, gl.canvas.width, gl.canvas.height ) : new Vector4();
 	const currentViewport = gl.canvas ? new Vector4( 0, 0, gl.canvas.width, gl.canvas.height ) : new Vector4();

This change causes everything to work again.

To Reproduce

Steps to reproduce the behavior:

  1. Go to https://snack.expo.io/@switt/threejs-renderer-initialization-bug-example
  2. Use a mobile device running Expo Go client to scan the QR code to run it.
  3. See Alert “Renderer failed”, with error message of “null is not an object (evaluating ‘e.canvas.width’)”
  4. Change package.json version of “three” to something like “~0.122”
  5. See a spinning cube.

Code

import { ExpoWebGLRenderingContext, GLView } from 'expo-gl';
...
      <GLView
        style={{ flex: 1 }}
        onContextCreate={async (gl: ExpoWebGLRenderingContext) => {
          const {
            drawingBufferWidth: width,
            drawingBufferHeight: height,
          } = gl;

          const renderer = new Renderer({ gl }) // This will fail
          renderer.setSize(width, height)
          renderer.setClearColor(sceneColor)
      }}
/>

Live example

Expected behavior

A clear and concise description of what you expected to happen.

  • Renderer created successfully

Screenshots

If applicable, add screenshots to help explain your problem (drag and drop the image).

Platform:

  • Device: Mobile Expo React-Native, SDK 39-41
  • OS: iOS and Android
  • Browser: Expo GLView React-Native
  • Three.js version: “^0.128.0” (not sure what last working version was, but 0.122 did work)

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7

github_iconTop GitHub Comments

1reaction
gkjohnsoncommented, May 13, 2021

I have used canvas since the default WebGL viewport values are the width and height of the canvas. Note that the MDN docs also state that drawingBufferWidth is not always equal canvas.width.

Right but I don’t think those docs really account for the subtlety in behavior when the system can’t match the drawing buffer to the canvas size. Consider the following test that tries to create a webgl context from a canvas with a width and height that is larger than the browser can handle:

canvas = document.createElement('canvas');
canvas.width = canvas.height = 20000;
gl = canvas.getContext('webgl');

// Chrome: null gl context is returned
// Firefox: resizes draw buffer, logs "20000, 10000"
console.log( canvas.width, gl.drawingBufferWidth );

// Firefox: logs [ 0, 0, 10000, 10000 ]
console.log( gl.getParameter(gl.SCISSOR_BOX) );

So in chrome if you try to initialize a gl context to something too large it just fails. But in Firefox the draw buffer is resized and you can see that the default scissor box size matches the gl.drawingBuffer* value rather than the canvas dimensions.

Perhaps the most robust thing to do here is just initialize the scissor and viewport vectors using the returned gl.getParameter values, instead, which should also fix the compatibility issue with expo.

0reactions
Mugen87commented, May 13, 2021

Perhaps the most robust thing to do here is just initialize the scissor and viewport vectors using the returned gl.getParameter values, instead, which should also fix the compatibility issue with expo.

That sounds good! Let me file a PR.

Read more comments on GitHub >

github_iconTop Results From Across the Web

three.js failing to use pre-created canvas - Stack Overflow
Three.js only throws this error in one place, and luckily it's doing something very simple: Getting a context from a canvas .
Read more >
WebGLRenderer – three.js docs
A canvas where the renderer draws its output. This is automatically created by the renderer in the constructor (if not provided already); you...
Read more >
Three.js Fundamentals
After we look up the canvas we create a WebGLRenderer . The renderer is the thing responsible for actually taking all the data...
Read more >
Getting started with WebGL - Web APIs | MDN
WebGL enables web content to use an API based on OpenGL ES 2.0 to perform 2D and 3D ... and working if (gl...
Read more >
Your First three.js Scene: Hello, Cube!
Not counting the import statement and comments, there are under twenty lines of code in total. That's all it takes to create a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found