【发布时间】:2015-08-02 07:12:21
【问题描述】:
我正在尝试寻找在不破坏场景本身的情况下清除场景中所有对象的方法。我知道命名对象是一种方法,然后当我们想要删除对象时,我们只需通过它的名称“获取”它。但是,我想找到一种快速的方法来清除场景中的所有对象,无论它们的名称如何。有简单的方法吗?谢谢!
【问题讨论】:
标签: javascript three.js
我正在尝试寻找在不破坏场景本身的情况下清除场景中所有对象的方法。我知道命名对象是一种方法,然后当我们想要删除对象时,我们只需通过它的名称“获取”它。但是,我想找到一种快速的方法来清除场景中的所有对象,无论它们的名称如何。有简单的方法吗?谢谢!
【问题讨论】:
标签: javascript three.js
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);
});
}
【讨论】:
可以遍历场景的子对象,一个一个移除。
按照 cmets 中的建议,这应该以相反的顺序完成,以免修改您正在迭代的元素。
while(scene.children.length > 0){
scene.remove(scene.children[0]);
}
注意:这只是对对象层次结构的快速而肮脏的清除。如果您计划大量执行此操作,您可能会在上面的代码中遇到内存泄漏,因为渲染器引用了对象的材质、纹理和几何图形。完整的场景清理更复杂,还有很多其他问题需要更详细:
【讨论】:
while(scene.children.length > 0){ scene.remove(scene.children[0]); }
遍历所有子对象并调用 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] 为空,那么if(!obj.material[prop]) 检查将捕获该值(因为空值是假值)。事实上,之前的 if/return 可以删除,obj.material[prop] !== null 可以缩短为obj.material[prop] 以有效处理所有情况。
我有一个更简洁的方法来做到这一点。我注意到 Object3D 的 remove 方法接受多个参数来移除对象。这允许我们通过利用函数的内置apply 方法修改调用以将每个元素用作单独的参数来使用整个children 数组。这样做是这样的:
scene.remove.apply(scene, scene.children);
【讨论】: