Significant Performance Drop and High CPU Usage with BatchedMesh

Hello,

I exported a building model from Revit in glTF format and merged meshes with the same materials to manage their visibility in Three.js using the BatchedMesh class. However, I’ve encountered a significant performance issue when rendering these merged meshes with BatchedMesh compared to using Mesh.

Performance Comparison:

  • BatchedMesh Rendering:
    • CPU Usage: ~40%
    • GPU Usage: ~30%
    • Frame Rate: ~20 FPS
  • Mesh Rendering:
    • CPU Usage: ~15%
    • GPU Usage: ~90%
    • Frame Rate: ~60 FPS

This drastic difference in performance is concerning, especially the high CPU load and low frame rate when using BatchedMesh. I’ve already set .perObjectFrustumCulled and .sortObjects to false in BatchedMesh, which, if set to true, leads to an even more severe frame rate drop.

Additionally, I’m using three-csm and postprocessing frameworks alongside Three.js.

System Configuration:

  • CPU: Intel i7-10700
  • GPU: NVIDIA RTX 2080 Super

Could someone help me understand why BatchedMesh increases the CPU overhead so significantly and suggest any possible optimizations or solutions to improve the frame rate?

Thank you!

BatchedMesh is relatively new so it’s entirely possible there are bugs, or you’ve hit a corner case.
Is there anything preventing you from using regular InstancedMesh?
BatchedMesh is more complex, but if you’re displaying a cad model, you may not need all that complexity…
Might be worth comparing the performance of each, and could be userful insight into diagnosing the issue.

Thank you for your suggestion! Let me clarify my situation with an example: In the building model, all walls are made of concrete and share the same material; however, most of these walls have unique geometric shapes, which prevents the use of InstancedMesh . For optimization purposes, it’s necessary to merge all the geometric data of the walls into one mesh. Yet, it is crucial to ensure that individual walls can be separately picked and have their visibility and color modified dynamically. This requirement makes BatchedMesh the only feasible option for my use case.

Are you updating things like visibility/color, every frame, or only when they change?

In my case, I simply loaded the models into the scene, without any changes to visibility or color settings.

Just send project here for tests

Thank you for your suggestion to share my project for testing. However, extracting the code is somewhat challenging as it involves only a part of my project. I developed this using TypeScript and used Vite for bundling. Additionally, I have implemented some of the glTF extensions proposed by the Cesium organization (EXT_instance_features, EXT_Mesh_features) to store data.

I am curious to see if anyone else has encountered similar issues. I will first attempt to address the problem myself. If I make any progress, I will submit a pull request. If I’m unable to resolve the issue, I will then consider isolating the code for further assistance.

1 Like

Cool. keep us posted!

In the past few days, I’ve tried to find a solution, but without success. I’ve uploaded the relevant code and models to GitHub. The models consist of 12 million triangles and 16 million vertices. Is such a high CPU performance cost necessary for BatchedMesh? I don’t think it should be. When rendering Batched3DModel in Cesium, I didn’t encounter such issues. I believe the mesh batching in Cesium and BatchedMesh should be quite similar, right?

Additionally, I’d like to mention that after the update to version 166, the performance consumption of BatchedMesh has worsened, and the frame rate has dropped further in the same scene.

Here is the link to the code and models: batched-mesh-performance-test

12 millions triangles too many. Maybe need to merge models with batched mesh and then break it to some parts of separated meshes with LOD and then will be rendered less triangles. Or dont merge and add LOD. I cant put the code, only advice.

12 million triangles isn’t a lot. If I render my already batched Mesh directly as a Mesh instead of dividing it into BatchedMesh, I can achieve 60 FPS (with 15% CPU usage and 90% GPU usage). However, using BatchedMesh, the frame rate drops to just 10 FPS (with 40% CPU usage and 30% GPU usage).

Batched and no batched have same amount of drawcalls.
Clicks on buttons inrease geometries
image

I’ve noticed something similar in my own project. Even when sortObjects and perObjectFrustumCulled are disabled, the performance of BatchedMesh in direct comparison to merged mesh drops by about 30% in my case. GPU usage is at 100% in case of merged mesh and 80% in case of BatchedMesh. DrawCalls are the same.

Have you found out more about this in the meantime?

Found the github discussion about the performance problems and posted an example: Significant Performance Drop and High CPU Usage with BatchedMesh · Issue #28776 · mrdoob/three.js · GitHub