I have a relatively simple scene containing thousands of meshes, and I am trying to switch from WebGLRenderer to WebGPURenderer. When I use WebGPURenderer, I encounter significant performance issues, and it feels roughly twice as slow as WebGLRenderer when rendering the same number of non-instanced meshes. Here’s the basic setup I am working with:
import MeshBasicNodeMaterial from 'three/src/materials/nodes/MeshBasicNodeMaterial.js'
const material = new MeshBasicNodeMaterial()
const helperGrid = new Mesh(new PlaneGeometry(totalGridWidth, totalGridWidth), material)
However, when I try to run this code with WebGLRenderer, I get the following error in the Chrome console: Uncaught TypeError: Cannot read properties of undefined (reading 'replace')
The code works fine with WebGPURenderer, but the performance issue with it prevents me from moving forward with my project. Is this performance difference specific to the WebGPURenderer, or is there something else I’m missing?
No onBeforeCompile I don’t use. You can see the performance sag if you set up a base scene with 1_000_000 base meshes and render them with WebGL first and then with WebGPU renderer.
Sure. Initially, I have simple setup where 20_000 non-instanced basic cube meshes rendered with WebGL, so personally I have smooth 60 FPS on my Mac with Apple Silicon M1 Pro. Then, when I switch to WebGPURenderer (just uncommenting the line) FPS drops exactly 4 times (15 FPS) with the same amount of meshes. So my next question would be, is this a hardware specific issue, or is it a software issue related to the implementation of the WebGPU technology?
1,000,000 meshes is a lot in either renderer — I’m not too surprised that would be unworkably slow without batching. As for why it’s a “less slow” in WebGLRenderer, they’re two separate renderers, with WebGPURenderer being relatively new and under active development… not to mention that the WebGPU API itself is still evolving. It could conceivably be either, I expect someone would need to spend some time digging into this to give you a full answer.
@tenkkov Would you mind creating an issue for this at the three.js repository? I have slightly simplified the code from your sandbox and created a fiddle with it. You can share it at GitHub when creating the issue: three.js dev template - module - JSFiddle - Code Playground
The performance problem in WebGPURenderer seems to be related to the way uniforms are managed. All 20.000 cubes share the same node builder state but each cube uses a UBO for its object scope uniforms (like the world matrix). This ends up in many setBindGroup()/ bindBufferBase() as well as writeBuffer()/bufferData() calls which significantly slow down the renderer.
Besides, the renderer seems to trigger a lot of redundant state updates although only the world matrix uniform value changes from cube to cube. That is separate issue that should be investigated as well.