performance: one single mesh with multiple materials or scene graph (multiple objects with single material) ?

I am working on a 3d viewer for buildings. Performance is the main concern here, for this the building elements have been abstracted, i.e. no frivolous meshes like door handles and the materials are restricted to lambert with color and a transparent material for windows.
Right now the building is built as a single mesh with multiple materials, which is very responsive, but we are running into secondary complications that deal with selecting objects and visibility (hide/unhide, isolate) of subobjects like buildingparts.
We have come a long way to get it working based on a single mesh, but I have to question the design decision of single mesh.

My question really boils down to this: given a complex model with a lot of triangles, which is the most optimal organisation of the scene based on the first principles of webgl ? Threejs implements a scene graph with all the fixings involved (iteration, visibilities, boundingbox etc), is there a compelling reason to not use it from a performance perspective ? Is there a compromise situation imaginable ?


Hello! How much draw calls in your scene now ? For each mesh three.js calculate frustum, matrix, uniforms. On my hardware 1000 draw calls take 9-10ms.

Drawcall is also per material even though you are drawing a single mesh. So you have a chance that you are drawing the same mesh multiple times of how many materials are attached to your mesh. (See this codepen for a demonstration. Draw call is printed in the console.

Also, opaque objects and transparent objects cannot be rendered at the same stage in general since they need to be sorted differently for blending, so there is another chance your batched mesh is broken and rendered in multiple times since you mentioned that the mesh has transparent materials as well.

I think rule of thumb here (since there might be some internal drawcall optimizations done by threejs that Iā€™m not aware), you want to batch the meshes that are share the same material that are share the same uniforms. If you need some diversity for those batched mesh then you should be able to via some tricks:

  • Use geometry attribute, pass variables per vertex and look them up in shader via vertex id or something (Something similar that is done in this instancing example)
  • Use texture as a map to store variables per vertex and look them in shader via texture coordinates (Something similar in threejs gpgpu examples)
  • If you need different textures for different part, then use texture atlas