How to change material of indivudal objects in THREE.js without the use of separate Meshes?

54 Views Asked by At

We have created a PCB Viewer in THREE.js and now we are looking to add some selection functionality to it. This is not a difficult task and I already have this functionality working though I am facing some performance issues. As we want all features of the PCB Layers (shapes) to be individually clickable and selectable (the colors change when selected) I figured each shape need their own THREE.js Mesh, so that we can control their Materials individually. Sure enough, it works as expected but of course it has massive performance issues as now, instead of having one combined mesh for all shapes on a PCB layer we have THOUSANDS.

I understand that having a lot of Meshes will degrade the performance. This is obviously true. Does anyone have any tips on how this could be done in a more performance efficient manner? For now it is enough for us to just change the colors of the indivudal shapes when they are clicked. Before my code changes we had all shapes in the same geometry on the same THREE Mesh. Can I somehow, in any way, keep this more simple structure but still manipulate inidivudal shapes/objects separately? To me it sounds far fetched but I am not too experienced in THREE

2

There are 2 best solutions below

0
Matheos On BEST ANSWER

So I ended up with the following solution:

  • I render "simple" meshes to my real scene, where a lot of objects are in the same geometries (objects sharing the same Material mostly)
  • I keep a "virtual scene" which I never render, on which I perform raycasting and check for intersections. In the virtual scene I have actual separate meshes for the individual objects.
  • When I find an intersection in the virtual scene, I clone that mesh object and add it to the real scene with the "selection material". I also apply a small offset to it so that it is slightly bigger than the original, to prevent z-fighting
  • When objects are deselected, I remove the selection objects from the real scene. I use user attributes to identify which ones they are. Each selection object also has a "back link" to the mesh from where it was cloned in the virtual scene. This way I can also check if I already have a selection of a certain object.
  • To know "Where" to the real scene to add my object (to which group - we have quite an advanced tree structure...) I also keep a user attribute in the virtual scene that "points to" (by id) the parent in the real world, to which I would add the selection object IF it is selected.

Hope this makes sense and that it will help someone else too

3
Don McCurdy On

The cost is not primarily the number of meshes, but the number of draw calls. Each draw call consists of a paired chunk of geometry (represented by THREE.Geometry) and a shader program (represented by THREE.Material). While three.js does allow multiple materials per mesh, the number of draw calls remains the same, so that won't solve your problem by itself.

What you probably need, instead, is to manipulate conceptual 'objects' without having separate THREE.Mesh and THREE.Material instances for each. For example, if you know the range of vertices selected, you can modify the vertex colors for that object to highlight it, or modify the vertex positions to move it.

It's also possible to store an original object ID as a vertex attribute for each object, and then you could use a custom shader material to apply certain changes in your material for different objects.

Example:

https://threejs.org/examples/#webgl_interactive_cubes_gpu