ngl: Shader error when upgrading to Three.js r112 (WebXR)

I wrote a custom minimal Viewer to embed NGL Representations into existing projects based on Three.js. Full control over the scene is maintained by the parent project, only the geometries are exported into a THREE.Group that can be freely manipulated. It was some effort but works quite well (see demo, branch ThreeJSViewer in my fork, glitch to play around with the API).

Besides needing this for another project I wanted to update @KJStrand A-Frame component and create some vanilla Three.js WebXR demo. WebXR is a first class citizen in Three.js now and it is really awesome even with a mobile headset like the Oculus Quest, but projects need to follow a few conventions (no forced camera movement, units are meters, floor plane for walking around an object etc.), so it would make sense to include NGL objects in a template like this. In the long run this should be done properly by enabling renderer.xr in NGL.Stage, but it will be some effort to make everything compatible (e.g. labels). Also, NGLs rendering pipeline is fairly advanced with its special treatment of still frames and the different cameras, so it might make sense to keep it completely separate (related issue).

Unfortunately, WebXR was included into Three.js with version 112, while we are on 111. I made a branch to make NGL compile up to 115, but between 111 and 112 something changed so that the shaders don’t work anymore. Stuff is rendered but stays invisible, and WebGL warnings like “GL ERROR :GL_INVALID_OPERATION : glDrawElements: Source and destination textures of the draw are the same.” are thrown (in Chrome, Firefox has slightly different warnings).

I did some research but have actually no idea what could cause this. Three.js changelogs and commits look unsuspicious to me. Maybe https://bugs.chromium.org/p/chromium/issues/detail?id=421695 is related, but it certainly happens on the version change, while this bug would probably be a deeper issue.

You can see the effect here: https://jussty.github.io/ngl-r112/examples/embedded.html or in the other examples.

A big disadvantage of including NGL into other projects is that Three.js version needs to match exactly. I don’t mind maintaining releases of ThreeJSViewer for different versions if you don’t want to have that burden in the main repo. A-Frame even ships with their own fork, but the 1.0.0 releases are also based off some WebXR enabled r111.5 which has the same problems.

Also I am certain the API could be even simpler, without needing references to renderer, camera AND scene, but since some of the low level shader utils need these objects for their magic I kept it in for now.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 25 (4 by maintainers)

Most upvoted comments

Your IDE may well know more about this than I do…

I’ve just submitted an issue to nglview and if that doesn’t raise any flags hopefully we can merge this soon.

@giagitom: How are you building your app at the moment - is it a javascript project with a package.json? If so you would be able to add ngl (and possibly three*) as deps and either use require('ngl') or import { Something } from 'ngl' depending on whether you’re using node-style or ES6 imports.

*My change would mean that adding ngl as a dep automatically brings in a compatible version of three - you could be explicit about which version of three you want by adding it as a dep and I think npm will try to use the same copy if versions are compatible, so your code would then be:

import { Stage } from 'ngl'   // Or var ngl = require('ngl')
import { Stuff } from 'three' // Or var three = require('three')

and they’d share a three instance (unless you specify an incompatible version)

You could test by replacing/adding the ngl dependency in your project as “fredludlow/ngl#pr-737”

@garyo - looking forward to hear if it works or not 😃

We’d also need to coordinate with nglview (cc’ing @hainm). It looks like nglview uses ES6 imports and webpack, the end result should be the same but when developing nglview npm would install three separately and webpack should bundle it in (if I understand it right) - this is definitely something that would need to work in order to proceed.

I guess our current situation stems from the fact that back in the day JS build tools were a lot less mature and not all the big libraries played nicely with npm/yarn

There are a few ways you might want to deploy NGL but I think it comes down to:

  1. A script tag pointing to a ngl.js including Three.js (either because you’re keeping it simple or want to make sure ngl is cached or whatever)
  2. Imported into your own project (either ES6 module import or the older require(‘ngl’) syntax) in which case supplying Three.js should be a concern of npm/yarn - by default it should ‘just work’ but give you the flexibility to declare Three as external/global/specific version or whatever

Proposal:

We move Three.js to a dependency (not a devDependency) with an appropriately specified version range. This means that when you npm install ngl, three will get installed alongside (and if versions are compatible your other code that uses Three will use the same instance).

We create three build targets:

  • A UMD modlue (.js file) including Three.js - (reproducing the current behaviour of ngl[.dev].js and still the quickest way to get “something” working in a web-page)
  • A UMD module (.js file) without Three.js - (cf. @garyo’s patch, but this becomes the ‘main’ entry in package.json too. so you can require(‘ngl’) from within node)
  • An ES6 module (.esm.js file) without Three.js - and leave it up to npm/yarn etc to satisfy the dependency - this allows e.g. import { Stage } from 'ngl' in an ES6 project

I made a quick attempt at this here: https://github.com/fredludlow/ngl/tree/pr-737

You can add this in npm as a git dependency if you want to try it: npm install -D fredludlow/ngl#pr-737 OR npm install -D fredludlow/ngl#82feda5 (the exact commit at time of writing)

Very minimal usage example here: https://github.com/fredludlow/ngl-module-test

If people are in favour of this approach there are a few TODOs

  • rollup.config.js needs a tidy
  • Naming of the built files in dist (and updating package.main and package.module)
  • Checking this doesn’t break 101 other things 😃 (like typescript in downstream projects!)

(If people aren’t in favour please speak up - I’m by no means an expert on this)

Indeed – you have to add three.js to your project (npm or yarn) and probably import Three from 'three' yourself. NGL just has Three set as a global dependency, so it doesn’t try to import it itself. If you look at the generated Javascript in (e.g.) build/js/ngl.esm.js you’ll see import lines like

import {Vector2, Vector3, ... Color, ...} from 'three';

so you have to provide three in your node_modules so it can be imported.

If I get some time I’ll try to put together a small webpack/three/NGL project but I’m pretty busy right now.