如何清除 THREE.JS 场景

Posted

技术标签:

【中文标题】如何清除 THREE.JS 场景【英文标题】:How do I clear THREE.JS Scene 【发布时间】:2015-08-02 07:12:21 【问题描述】:

我正在尝试寻找在不破坏场景本身的情况下清除场景中所有对象的方法。我知道命名对象是一种方法,然后当我们想要删除对象时,我们只需通过它的名称“获取”它。但是,我想找到一种快速的方法来清除场景中的所有对象,无论它们的名称如何。有简单的方法吗?谢谢!

【问题讨论】:

【参考方案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);
    );

【讨论】:

【参考方案2】:

可以遍历场景的子对象,一个一个移除。

按照 cmets 中的建议,这应该以相反的顺序完成,以免修改您正在迭代的元素。

while(scene.children.length > 0) 
    scene.remove(scene.children[0]); 

注意:这只是对对象层次结构的快速而肮脏的清除。如果您计划大量执行此操作,您可能会在上面的代码中遇到内存泄漏,因为渲染器引用了对象的材质、纹理和几何图形。完整的场景清理更复杂,还有很多其他问题需要更详细:

Three.js Collada - What's the proper way to dispose() and release memory (garbage collection)? THREE js proper removing object from scene (still reserved in HEAP) Deallocating heap objects when removing mesh from scene

【讨论】:

这个解决方案是不正确的,因为你正在迭代循环中修改的数组,所以可能会跳过一些元素(例如当你有两个子元素时),请替换为:while(scene.children.length > 0) scene.remove(scene.children[0]); 【参考方案3】:

遍历所有子对象并调用 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);

【讨论】:

如果 obj.material[prop] 为 null,我会看到“无法读取属性 'dispose' of null”错误消息。我通过将“if (typeof obj.material[prop].dispose === 'function')”行替换为“if (obj.material[prop]!== null && typeof obj.material[prop].处置 === '功能')" 如果obj.material[prop] 为空,那么if(!obj.material[prop]) 检查将捕获该值(因为空值是假值)。事实上,之前的 if/return 可以删除,obj.material[prop] !== null 可以缩短为obj.material[prop] 以有效处理所有情况。【参考方案4】:

我有一个更简洁的方法来做到这一点。我注意到 Object3D 的 remove 方法接受多个参数来移除对象。这允许我们通过利用函数的内置apply 方法修改调用以将每个元素用作单独的参数来使用整个children 数组。这样做是这样的:

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

【讨论】:

以上是关于如何清除 THREE.JS 场景的主要内容,如果未能解决你的问题,请参考以下文章

Three.js:无法将背景通道与轮廓通道相结合

Three.js:如何正确配置内存中的场景

three.js如何让场景中模型跟随鼠标旋转呀

Three.js-如何限制3D场景中的摄像机视图?

如何将fbxloader加载的摄像头添加到three.js中的场景?

如何在旋转场景中查找对象的全局位置 THREE.JS