Traverse Three.js Scene Graph to Find Objects
In Three.js, managing and locating specific 3D objects within a
complex hierarchy can be challenging. This article explains how to
efficiently traverse the entire Three.js scene graph using the built-in
traverse method, allowing you to search, filter, and
manipulate specific objects based on their properties, names, types, or
custom user data.
Understanding the Scene Graph
A Three.js scene is structured as a hierarchical tree graph. The root
node is typically the Scene object, which contains child
nodes like meshes, lights, cameras, and groups. Each of these child
nodes can, in turn, have their own children.
To find a specific object or perform an action on a subset of objects, you must recursively visit every node in this tree.
Using the traverse
Method
Three.js provides a built-in method called traverse on
all objects that inherit from Object3D. When you call
traverse on a parent object (such as the main
Scene), it executes a callback function for the parent and
all of its descendants recursively.
Here is the basic syntax:
scene.traverse((object) => {
// This function runs for every object in the scene
console.log(object.type);
});Finding Objects by Type
To perform actions on specific types of objects, such as meshes or lights, check the properties of the object inside the callback:
scene.traverse((object) => {
if (object.isMesh) {
// Apply changes only to meshes
object.material.color.setHex(0xff0000);
}
});Using flags like isMesh, isLight, or
isGroup is highly performant and the recommended way to
filter by type in Three.js.
Finding Objects with Custom Properties
You can also use the userData object to store custom
identifiers and search for them during traversal. This is useful for
identifying interactive objects.
// Example: Mark an object as interactive when creating it
myMesh.userData.isInteractive = true;
// Later, search the scene for interactive objects
const interactiveObjects = [];
scene.traverse((object) => {
if (object.userData && object.userData.isInteractive) {
interactiveObjects.push(object);
}
});Built-in
Shortcuts: getObjectByName and
getObjectById
If you only need to find a single object and you already know its name or unique ID, Three.js provides optimized shortcut methods that handle the traversal internally.
Finding by Name
Assign a unique name to your object:
const playerMesh = new THREE.Mesh(geometry, material);
playerMesh.name = "player_character";
scene.add(playerMesh);Retrieve it later from anywhere in the scene graph:
const player = scene.getObjectByName("player_character");
if (player) {
// Object found
}Finding by ID
Every Object3D is assigned a unique auto-incremented ID
upon creation. You can retrieve an object directly using this ID:
const objectId = myMesh.id;
const retrievedObject = scene.getObjectById(objectId);Performance Considerations
While traversal is highly useful, it can be performance-heavy if executed frequently.
- Avoid Traversal in the Render Loop: Do not call
scene.traverseinside yourrequestAnimationFrameloop. This will cause frame drops in complex scenes. - Cache Results: Traverse the scene once during initialization or after loading a model, and store references to the target objects in an array or object for quick access later.