three.js icon indicating copy to clipboard operation
three.js copied to clipboard

WebGPURenderer's Matrix4 side-effects break tree-shaking

Open CodyJasonBennett opened this issue 3 years ago • 4 comments
trafficstars

WebGPURenderer has side-effects that directly modify THREE.Matrix4 that were introduced in https://github.com/mrdoob/three.js/pull/20283. This is a bit problematic since those side-effects can't be tree-shaken, and they will bundle alongside threejs in client/server bundles (these can be code-split to be imported from multiple pages/bundles). This can break apps that utilize both WebGLRenderer and WebGPURenderer (like a blog or somewhere you'd have a lot of demos).

I discovered this by importing a flatbundle of three/examples/jsm (from #23368) but you can reproduce by importing the renderer individually:

import { WebGPURenderer } from 'three/examples/jsm/renderers/webgpu/WebGPURenderer'

image

CodyJasonBennett avatar Jan 28 '22 22:01 CodyJasonBennett

I've outlined an alternative approach that would also solve the side-effects issue: https://github.com/mrdoob/three.js/issues/20276#issuecomment-687800862

Mugen87 avatar Jan 29 '22 08:01 Mugen87

Looking at https://github.com/mrdoob/three.js/blob/dev/examples/jsm/renderers/webgpu/WebGPURenderer.js#L251-L252, I think the way to solve this (including https://github.com/mrdoob/three.js/pull/24383) would to do the following:

  1. Add Camera.ndcProjectionMatrix property,
  2. Add a parameter ndc = true/false to Frustum.setFromProjectionMatrix method.

Looking on these lines again, maybe we even can move NDC-related changes entirely into 2 without doing 1...

LeviPesin avatar Jul 23 '22 09:07 LeviPesin

What happens if WebGPU camera matrices are used in WebGL? I'm not sure I understand the relationship between the back-end's clipping space and the resulting projection matrices.

CodyJasonBennett avatar Aug 05 '22 21:08 CodyJasonBennett

What happens if WebGPU camera matrices are used in WebGL?

Near-plane clipping will occur at the wrong distance.

WestLangley avatar Aug 06 '22 00:08 WestLangley

Regarding https://github.com/mrdoob/three.js/issues/25823 this issue is not only problematic for tree-shaking, there are also side effects if an app wants to switch from WebGLRenderer to WebGPURenderer and vice versa.

A global like like suggested in https://github.com/mrdoob/three.js/issues/20276#issuecomment-687800862 would support this use case but not when both renderers are used at the same time (e.g. when rendering to different canvases).

Mugen87 avatar Apr 13 '23 08:04 Mugen87

I think the approach described in https://github.com/mrdoob/three.js/issues/23372#issuecomment-1193097640 is the best. Maybe we can try it?

LeviPesin avatar Apr 13 '23 09:04 LeviPesin

We really need to update Camera.updateProjectionMatrix() out of rendering? Couldn't this be moved inside Renderer.render( scene, camera ) ? This could even simplify the examples...

sunag avatar May 21 '23 03:05 sunag

@sunag Do you mean recomputing projectionMatrix every render?

mrdoob avatar May 23 '23 07:05 mrdoob

@sunag Do you mean recomputing projectionMatrix every render?

I think we can have a check to see if there is a need to update, something like const needsUpdateProjectionMatrix = ....

But my biggest concern would not be just simplifying, but as we have the strategy of preserving the API the use of Camera.updateProjectionMatrix() would be incompatible without adding a property (static or not) that we could change between the backend of WebGPU and WebGL because of the use of Matrix4.makePerspective(). This issue could be solved easily if we moved the Camera.updateProjectionMatrix() to render() in an optimized way as I explained above about the needsUpdate.

Maybe we could include a Camera.projectionMatrixAutoUpdate = true to preserve compatibility... that last one is just an idea that just came to me.

sunag avatar May 23 '23 13:05 sunag

The scenario I came across recently was the WebGPU hack: https://github.com/mrdoob/three.js/blob/c0f9764c0224e97f33f2487c4123b96429e18d21/examples/jsm/renderers/webgpu/WebGPUBackend.js#L98

Being applied only after WebGPU.init() have been completed. The problem is that until this happens the Camera.updateProjectionMatrix() has already been computed using the WebGL version. The suggestion above would solve this.

sunag avatar May 24 '23 00:05 sunag