How to Remove Objects from a Three.js Scene
In Three.js, removing an object from the scene graph during runtime
requires more than just calling the .remove() method. To
prevent memory leaks and ensure optimal performance, you must also
properly dispose of the object’s geometry, materials, and textures. This
article provides a straight-to-the-point guide on how to safely detach
an object from your scene, release its WebGL resources, and clean up GPU
memory.
Step 1: Remove the Object from the Parent
The first step is to disconnect the object from the scene graph so it
is no longer rendered. You do this by calling the remove()
method on the object’s parent (which is often the scene
itself).
scene.remove(mesh);Step 2: Dispose of Geometries and Materials
Simply removing a mesh from the scene does not free up the GPU memory
allocated for its geometry and materials. To prevent memory leaks, you
must explicitly call the .dispose() method on these
components.
// Dispose of geometry
if (mesh.geometry) {
mesh.geometry.dispose();
}
// Dispose of material(s)
if (mesh.material) {
if (Array.isArray(mesh.material)) {
mesh.material.forEach(material => disposeMaterial(material));
} else {
disposeMaterial(mesh.material);
}
}Step 3: Dispose of Textures
If your materials use textures, those textures must also be disposed of individually to free up VRAM.
function disposeMaterial(material) {
// Dispose of textures associated with the material
for (const key in material) {
if (material[key] && typeof material[key].dispose === 'function') {
material[key].dispose();
}
}
// Dispose of the material itself
material.dispose();
}Creating a Reusable Clean-up Function
If you need to remove a complex object with nested children (like a loaded GLTF model), you should traverse the object hierarchy to ensure every child mesh is fully cleaned up.
function safelyRemoveObject(objectToRemove) {
objectToRemove.traverse((child) => {
if (child.isMesh) {
// Clean up geometry
if (child.geometry) {
child.geometry.dispose();
}
// Clean up materials and textures
if (child.material) {
if (Array.isArray(child.material)) {
child.material.forEach((material) => {
cleanMaterial(material);
});
} else {
cleanMaterial(child.material);
}
}
}
});
// Remove from parent
if (objectToRemove.parent) {
objectToRemove.parent.remove(objectToRemove);
}
}
function cleanMaterial(material) {
// Dispose of any textures
for (const key in material) {
if (material[key] && material[key].isTexture) {
material[key].dispose();
}
}
// Dispose of the material
material.dispose();
}Using this recursive approach ensures that all GPU resources associated with the target object and its hierarchy are completely freed, maintaining high performance in your Three.js application.