Best practice for visualization mode switching (layers vs scene traversal) in large Three.js scenes?

I’m building a CAD / engineering-style viewer in Three.js with hundreds of meshes and a fixed set of visualization modes:

  • Shaded
  • Wireframe
  • Hidden Line
  • Silhouette / Outline
  • Translucent
  • Line / Centerline

Current approach (hybrid)

We currently use a mix of two techniques:

1. Pre-created geometry + layers
For example, for Line / Centerline mode, I create the line representation at the time the mesh is created, assign it to a separate layer, and simply toggle visibility by switching the camera layer.

2. Scene traversal + material modification
For other modes (e.g. Translucent), I traverse the scene and modify materials, with reset / restore logic on every mode switch.
Example:

public applyTranslucent(alpha: number = 0.2): void {
  this.resetToClean();

  this.forEachMesh((mesh) => {
    this.modifyMaterials(mesh, (mat) => {
      mat.transparent = true;
      mat.opacity = alpha;
    });
  });
}

This works, but adds material state management, traversal cost, and complexity as the number of modes grows.


Proposed approach

We’re considering moving to a pure layer-based approach:

  • Pre-create required representations once when geometry is created
  • Assign each representation to its own layer
  • Switch visualization modes by switching camera layers
  • Keep silhouette / outline as a post-processing effect only

This means multiple representations exist in the scene, but only one layer is rendered at a time.


Questions

  1. Is a layer-based / precomputed representation approach recommended for this type of use case?
  2. From a scalability and performance perspective, is it generally better to:
  • pay an upfront memory cost, or
  • traverse the scene and mutate materials on each mode switch?
  1. Are there any known pitfalls with layers when working with large scenes (hundreds or thousands of meshes)?
2 Likes

This is a complex question.

What your Proposed approach gives you, is the ability to have multiple modes exist at once. So i could have an object that has an arbitrary set of those visualizations.

The downside is that the renderer will still be checking .layer on all the disabled modes every frame. This is a downside to relying on the .layer mechanism, that it is not hierarchical, and requires layer to be set on all the objects themselves.. and that the objects are still processed every render if only to determine layer visibility.
So the number of objects touched during render is N number of objects times M modes…

However, you can make a parent for each of these modes and toggle the .visible flag on the parent to cut off the traversal of modes you know aren’t currently visible. This might be a practical kind of middle ground.

The memory consumption is less concerning to me.
There will still be material sharing, and the geometries of the meshes will still be shared.. so there isn’t a Huge amount of overhead in having duplicate scenegraphs… it’s just that they will have to be kept synchronized, or updated/reconstructed on the fly as the base object is modified.

3 Likes

@manthrax
Thanks, this is very helpful — especially the point about layer checks still happening for every object each frame. I was not aware of this.

Using a mode-specific parent/root and toggling its .visible flag makes a lot of sense as a middle ground.