How to remove lights from cloned scene

Hi there,

i’m trying to remove my directionalLight and spotLights from the scene before exporting it. My attemt was to clone the scene and remove the objects equal to type “SpotLight” and “DirectionalLight” and then use this scene in the GLTFExporter. Unfortunatly i get this error: Uncaught TypeError: Cannot read properties of undefined (reading ‘traverse’)
The traversing is working, i tested it with a simple log.

Here’s part of my code:

  // Traverse scene before download
  const clonedScene = scene.clone();
  clonedScene.traverse((obj) => {
    if (obj.type === "SpotLight" || obj.type === "DirectionalLight") {
      clonedScene.remove(obj);
    }
  });

  function download() {
    const exporter = new GLTFExporter();
    exporter.parse(
      [clonedScene, camera],
      function (result) {
        saveArrayBuffer(result, string);
      },
      //called
      function (error) {
        console.error("Error exporting GLTF:", error);
        alert("An error occurred during export. See console for details.");
      },
      { binary: true }
    );
  }

What am i doing wrong?

Greetings Tom

might not be the problem but this code is not correct

  clonedScene.traverse((obj) => {
    if (obj.type === "SpotLight" || obj.type === "DirectionalLight") {
      clonedScene.remove(obj)
    }

it implies that any light has to be a direct child of clonedScene, but once it’s grouped it won’t be.

2 Likes

In addition to @drcmda , another possible explanation is that when you remove the element, this confuses the .traverse(...) method. Traverse expects some number of children, but when you remove a light, the number of children reduces and traverse does not know this and goes outside the list. Generally, when a tree structure is traversed recursively, it is highly suggested to not modify it in a way that will confuse the traversing.

If this is the case, only collect lights during traversal. Then outside traversal, remove them one by one. This should be safe.

2 Likes

Ahh thanks for the tip, in my case that works because the lights are direct childs but i’ll change that:)

You were right, changing it to remove the lights afterwards works, thank you!!

const clonedScene = scene.clone();
const lights = [];
clonedScene.traverse((obj) => {
      if (
        obj.type === "SpotLight" ||
        obj.type === "DirectionalLight" ||
        obj.type === "AmbientLight"
      ) {
        lights.push(obj);
      }
    });
for (let i = 0; i < lights.length; i++) {
clonedScene.remove(lights[i]);
}
1 Like

Your code will break if the light is deeper in the tree and not a direct child of clonedScene. Consider this instead:

const lights = [];
clonedScene.traverse((obj) =>obj.isLight&&lights.push(obj))
lights.forEach(light=>light.parent.remove(light))
1 Like

I changed my code, thanks alot for the help!!:slight_smile:

1 Like