Closed sophiedeziel closed 4 months ago
Visit the preview URL for this PR (updated for commit 796c36a):
https://gcode-preview--pr164-feature-batched-mesh-e3sllffe.web.app
(expires Sat, 20 Jul 2024 03:38:25 GMT)
🔥 via Firebase Hosting GitHub Action 🌎
Sign: 59bd114ae4847b32c2bba0b68620b9069a3e3531
I was not looking at the right place for performance improvements!
Yes, the initial render is a bit slower. But to the human eye, it is not noticeable.
However, each animation frame gets an amazing improvement! I went back to check after I noticed a great slowdown of my web app, and heat up of my laptop. I had skipped frames and I wondered if this PR had render improvements that I did not notice.
It does make a great difference when gcode-preview is embeded in a heavy framework.
This PR would replace https://github.com/remcoder/gcode-preview/pull/165 completely, since it's reducing the number of materials in a similar way.
Archiving the initial PR description because I'll rewrite it:
I'll start by saying that the results are disappointing at first.
It seems to have made the performance worse, but it may also be mis-use of the feature or a mistake in the code.
My theory is that batchMesh is good when adding meshes to the scene individually. But we're already using groups for that. What we gain by reducing the number of new materials is insignificant compared to the overhead of instanciating a batchedMesh and adding geometries to it.
From the docs:
Use BatchedMesh if you have to render a large number of objects with the same material but with different world transformations and geometry
I think there's no improvement because the geometries don't have different world transformations.
I'll take those learnings and try to apply the same logic of a color index, but to only instanciate one material per color. The improvement may not be noticeable, but we'll reduce the memory footprint.
Now, looking at a ~300ms window:
Very cool results! Would this improvement be mostly felt with larger models? If it can reduce the sluggishness with large models that would be super!
I tested this with an 8MB large model and got an exception:
Uncaught (in promise) Error: BatchedMesh: Reserved space request exceeds the maximum buffer size.
at BatchedMesh.addGeometry (three.module.js:33220:10)
at Mt.batchGeometry (gcode-preview.es.js:1:47533)
at gcode-preview.es.js:1:46092
at Array.forEach (<anonymous>)
at Mt.addTubeLine (gcode-preview.es.js:1:46015)
at Mt.doRenderExtrusion (gcode-preview.es.js:1:43644)
at Mt.renderLayer (gcode-preview.es.js:1:42984)
at Mt.render (gcode-preview.es.js:1:41315)
at HTMLCanvasElement.<anonymous> (demo.js:311:13)
There's probably something I need to learn about javascript exceptions!
This is most likely where it is triggered, but I'm catching errors.
Very cool results! Would this improvement be mostly felt with larger models? If it can reduce the sluggishness with large models that would be super!
The larger the model, the most noticeable the improvement is!
I notice it is much smoother (higher FPS) with batchedMesh!
However I consistently run into the above error with files over 4.5MB.
I can fix it by raising maxVertexCount
(second param) in new BatchedMesh(200, 10000, undefined, material);
I can fix it by raising
maxVertexCount
(second param) innew BatchedMesh(200, 10000, undefined, material);
Yes, ideally the count should be calculated to avoid over-allocating and to make sure it can support geometries of any size.
I'll try a refactor because I realized that this may not play very well with the progressive rendering. There would be some benefits to generate all geometries first and then add them to BatchedMesh instances in one go. There are memory tradeoffs that I want to measure too.
I wanted to test the limits:
The initial render is slow, but the line one (non-tube) takes 2200ms.
It runs at 15 FPS, which is way smoother than expected! The develop branch can barely do 3 or 4 FPS.
This branch:
Before:
With the last commits that create fewer batchMeshes, the multicolor benchy's render frames are almost cut in half. Went from ~5.75ms to ~2.90 on average
Part of #95
Using BatchedMesh to group all meshes of the same material to reduce the number of draw calls.
The initial render time is slightly higher, but not human noticeable. However, performance gains on each animation frame is significantly better. It's about 5x faster. See comments below. It makes a great difference when large models are rendered, especially when the viewer is embedded in a framework that's on the heavy side.
Changes:
BatchedMesh
andBatchedMesh#batchGeometry
BatchedMesh
reserves a buffer ahead of time with the constructor, I tried to find a good balance. It could be tweaked or pre-calculated in the future.