如何清空THREE.JS场景。

25

我正在尝试找到一种在不销毁场景本身的情况下清除场景中所有对象的方法。我知道给对象命名是一种方法,然后当我们想要删除该对象时,只需通过名称“获取”它即可。但是,我希望找到一种快速清除场景中所有对象的方法,而不管它们的名称如何。有简单的方法吗?谢谢!

我正在寻求在不破坏场景本身的情况下清除场景中所有对象的方法。尽管我知道可以通过为对象命名来实现此目的,然后在需要删除对象时使用其名称。但是,我想找到一种更快速的方法,可清除场景中所有对象,而不考虑它们的名称。是否有这样的方法呢?谢谢!
6个回答

28

您可以遍历场景的子对象并逐个删除它们。

正如评论中建议的那样,应该按相反的顺序进行操作,以免修改您正在迭代的元素。

while(scene.children.length > 0){ 
    scene.remove(scene.children[0]); 
}
注意:这只是一个快速而简单的对象层次清理。如果您打算经常这样做,由于渲染器对对象材质、纹理和几何体有引用,因此使用上述代码会导致内存泄漏的风险。完整场景的清理更加复杂,并且还有许多其他问题需要详细了解:

5
这个解决方案是不正确的,因为你正在遍历一个在循环中被修改的数组,所以一些元素可能会被跳过(例如当children里有两个元素时),请替换成: scene.remove(scene.children[0]); }``` - Alleo

23

我有一种更简洁的做法。我注意到Object3Dremove方法接受多个参数以进行对象移除。这使我们可以通过修改调用以将每个元素作为单独的参数使用来使用整个children数组,从而利用函数的内置apply方法。操作如下:

scene.remove.apply(scene, scene.children);

16

遍历所有的子元素并调用其几何、材质和纹理的dispose方法。以下是我的解决方案。

function clearThree(obj){
  while(obj.children.length > 0){ 
    clearThree(obj.children[0]);
    obj.remove(obj.children[0]);
  }
  if(obj.geometry) obj.geometry.dispose();

  if(obj.material){ 
    //in case of map, bumpMap, normalMap, envMap ...
    Object.keys(obj.material).forEach(prop => {
      if(!obj.material[prop])
        return;
      if(obj.material[prop] !== null && typeof obj.material[prop].dispose === 'function')                                  
        obj.material[prop].dispose();                                                      
    })
    obj.material.dispose();
  }
}   

clearThree(scene);

1
如果obj.material[prop]为null,我会看到“无法读取null的属性'dispose'”错误消息。我通过将“if(typeof obj.material [prop] .dispose ==='function')”行替换为“if(obj.material [prop]!== null && typeof obj.material [prop] .dispose ==='function')”来解决问题。 - Andrej
如果obj.material [prop]为空,那么它将被 if(!obj.material [prop])检查捕获(因为null是falsy值)。实际上,以前的 if/return 可以被移除,并且obj.material [prop]!== null可以缩短为obj.material [prop]以高效地处理所有情况。 - Jonathan Gray

1
以下方法对我清除场景也有效:
const n = scene.children.length - 1; 
for (var i = n; i > -1; i--) {
    scene.remove(scene.children[i]); 
} 

在逆序迭代项目时,不会出现当前数组索引的问题。


0

一定要删除所有东西,特别是纹理贴图。

    function removeObjectsWithChildren(obj){

        if(obj.children.length > 0){
            for (var x = obj.children.length - 1; x>=0; x--){
                removeObjectsWithChildren( obj.children[x]);
            }
        }

        if (obj.geometry) {
            obj.geometry.dispose();
        }

        if (obj.material) {
            if (obj.material.length) {
                for (let i = 0; i < obj.material.length; ++i) {

    
                    if (obj.material[i].map) obj.material[i].map.dispose();
                    if (obj.material[i].lightMap) obj.material[i].lightMap.dispose();
                    if (obj.material[i].bumpMap) obj.material[i].bumpMap.dispose();
                    if (obj.material[i].normalMap) obj.material[i].normalMap.dispose();
                    if (obj.material[i].specularMap) obj.material[i].specularMap.dispose();
                    if (obj.material[i].envMap) obj.material[i].envMap.dispose();

                    obj.material[i].dispose()
                }
            }
            else {
                if (obj.material.map) obj.material.map.dispose();
                if (obj.material.lightMap) obj.material.lightMap.dispose();
                if (obj.material.bumpMap) obj.material.bumpMap.dispose();
                if (obj.material.normalMap) obj.material.normalMap.dispose();
                if (obj.material.specularMap) obj.material.specularMap.dispose();
                if (obj.material.envMap) obj.material.envMap.dispose();

                obj.material.dispose();
            }
        }

        obj.removeFromParent();

        return true;
    }

-1

你需要使用scene.clear()。这里是示例代码,首先将其变成一个函数,然后每次想要更改对象时调用该函数。

function loadscene(path)
{
    scene.clear();
    loader.load(path,function(gltf)
    {
        const model = gltf.scene;
        model.position.set(0,0,0);
        model.rotation.set(0,0,0);
        model.scale.set(1,1,1);
        scene.add(model);
        animate();
    }, 
    undefined, function(e)
    {
        console.error(e);
    });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接