Three.js Collada - dispose() 和释放内存(垃圾收集)的正确方法是啥?
Posted
技术标签:
【中文标题】Three.js Collada - dispose() 和释放内存(垃圾收集)的正确方法是啥?【英文标题】:Three.js Collada - What's the proper way to dispose() and release memory (garbage collection)?Three.js Collada - dispose() 和释放内存(垃圾收集)的正确方法是什么? 【发布时间】:2016-01-14 02:58:01 【问题描述】:我已经通过 ColladaLoader 成功导入了一个 .dae 场景。
问题是,我需要在几个 .dae 文件之间切换。
我似乎无法正确实现 dispose 方法。
dae.traverse(function(obj)
console.log('unloading ' + obj.id);
scene.remove(obj);
if(obj.geometry)
obj.geometry.dispose();
if(obj.material)
obj.material.dispose();
if(obj.mesh)
obj.mesh.dispose();
if(obj.texture)
obj.texture.dispose();
);
scene.remove(dae);
我可能做错了什么?
提前非常感谢!
编辑:
这是完整的代码。
var renderer = null;
var scene = null;
var camera = null;
var controls = null;
var dae = null;
//var loader = null;
function init()
renderer = new THREE.WebGLRenderer( alpha: 1, antialias: true, clearColor: 0xffffff );
renderer.setSize( 800, 600 );
var elem = $('.main3d')[0];
elem.appendChild( renderer.domElement );
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 20, 800/600, 1, 1000 );
camera.position.set( 0, -100, 50 );
//camera.lookAt( scene.position );
controls = new THREE.TrackballControls( camera, renderer.domElement );
var light = new THREE.AmbientLight( 0xffffff ); // soft white light
scene.add( light );
threeAnimate();
function load(url)
loader = new THREE.ColladaLoader();
loader.load(url, function (collada)
dae = collada.scene;
scene.add(dae);
);
function unload()
dae.traverse(function(obj)
console.log('unloading ' + obj.id);
scene.remove(obj);
if(obj.geometry)
obj.geometry.dispose();
if(obj.material)
obj.material.dispose();
if(obj.mesh)
obj.mesh.dispose();
if(obj.texture)
obj.texture.dispose();
);
scene.remove(dae);
var animFrame = null;
function animate()
animFrame = requestAnimationFrame( threeAnimate );
renderer.render( scene, camera );
controls.update();
【问题讨论】:
【参考方案1】:这应该可以完成工作:
function disposeNode (node)
if (node instanceof THREE.Mesh)
if (node.geometry)
node.geometry.dispose ();
if (node.material)
if (node.material instanceof THREE.MeshFaceMaterial)
$.each (node.material.materials, function (idx, mtrl)
if (mtrl.map) mtrl.map.dispose ();
if (mtrl.lightMap) mtrl.lightMap.dispose ();
if (mtrl.bumpMap) mtrl.bumpMap.dispose ();
if (mtrl.normalMap) mtrl.normalMap.dispose ();
if (mtrl.specularMap) mtrl.specularMap.dispose ();
if (mtrl.envMap) mtrl.envMap.dispose ();
if (mtrl.alphaMap) mtrl.alphaMap.dispose();
if (mtrl.aoMap) mtrl.aoMap.dispose();
if (mtrl.displacementMap) mtrl.displacementMap.dispose();
if (mtrl.emissiveMap) mtrl.emissiveMap.dispose();
if (mtrl.gradientMap) mtrl.gradientMap.dispose();
if (mtrl.metalnessMap) mtrl.metalnessMap.dispose();
if (mtrl.roughnessMap) mtrl.roughnessMap.dispose();
mtrl.dispose (); // disposes any programs associated with the material
);
else
if (node.material.map) node.material.map.dispose ();
if (node.material.lightMap) node.material.lightMap.dispose ();
if (node.material.bumpMap) node.material.bumpMap.dispose ();
if (node.material.normalMap) node.material.normalMap.dispose ();
if (node.material.specularMap) node.material.specularMap.dispose ();
if (node.material.envMap) node.material.envMap.dispose ();
if (node.material.alphaMap) node.material.alphaMap.dispose();
if (node.material.aoMap) node.material.aoMap.dispose();
if (node.material.displacementMap) node.material.displacementMap.dispose();
if (node.material.emissiveMap) node.material.emissiveMap.dispose();
if (node.material.gradientMap) node.material.gradientMap.dispose();
if (node.material.metalnessMap) node.material.metalnessMap.dispose();
if (node.material.roughnessMap) node.material.roughnessMap.dispose();
node.material.dispose (); // disposes any programs associated with the material
// disposeNode
function disposeHierarchy (node, callback)
for (var i = node.children.length - 1; i >= 0; i--)
var child = node.children[i];
disposeHierarchy (child, callback);
callback (child);
你使用它
disposeHierarchy (YOUR_OBJECT3D, disposeNode);
【讨论】:
哇!说的很全面!我会检查一下。感谢您花时间回答! 我也想知道答案是基于您自己的研究还是您有任何来源。再次感谢! 很棒的答案!我能够使用 disposeHierarchy() 函数释放 700MB+!简直了不起的人。非常感谢。我希望这个答案也对其他人有所帮助。 我发布了另一个问题(与这个问题有点相关)。如果您能分享您对该主题的知识,那就太棒了!提前致谢! @gaitat 光照类没有 dispose 方法【参考方案2】:我调整了 gaitat 已经很棒的答案,只使用现在内置的场景遍历功能,删除 $ 并处理 MultiMaterial。为什么,哦为什么没有内置的内存清理三!?当你执行scene.dispose()时,它当然应该这样做。我仍在尝试追踪我正在使用的更多纹理,但根据renderer.info.memory.textures
this.disposeNode = function (parentObject)
parentObject.traverse(function (node)
if (node instanceof THREE.Mesh)
if (node.geometry)
node.geometry.dispose();
if (node.material)
if (node.material instanceof THREE.MeshFaceMaterial || node.material instanceof THREE.MultiMaterial)
node.material.materials.forEach(function (mtrl, idx)
if (mtrl.map) mtrl.map.dispose();
if (mtrl.lightMap) mtrl.lightMap.dispose();
if (mtrl.bumpMap) mtrl.bumpMap.dispose();
if (mtrl.normalMap) mtrl.normalMap.dispose();
if (mtrl.specularMap) mtrl.specularMap.dispose();
if (mtrl.envMap) mtrl.envMap.dispose();
mtrl.dispose(); // disposes any programs associated with the material
);
else
if (node.material.map) node.material.map.dispose();
if (node.material.lightMap) node.material.lightMap.dispose();
if (node.material.bumpMap) node.material.bumpMap.dispose();
if (node.material.normalMap) node.material.normalMap.dispose();
if (node.material.specularMap) node.material.specularMap.dispose();
if (node.material.envMap) node.material.envMap.dispose();
node.material.dispose(); // disposes any programs associated with the material
);
【讨论】:
这就是它没有被自动删除的原因。 Delocating heap objects...。程序员必须参与进来,因为它并不像你想象的那么简单。在足够大的项目中,事情变得复杂,你最终会重复使用场景之间的材质、几何形状甚至网格(不是开玩笑,你最终可能会完成上述所有操作)。所以如此愉快地删除东西只会带来痛苦和悲伤。拥有学习曲线并且必须以程序员的身份参与进来,可以防止你犯愚蠢的错误。 现在官方文档中有一篇非常不错的关于处理东西的文章:threejs.org/docs/index.html?q=dispose#manual/en/introduction/…【参考方案3】:根据此处的答案,此代码处理材料数组。
function disposeNode(parentObject)
parentObject.traverse(function (node)
if (node instanceof THREE.Mesh)
if (node.geometry)
node.geometry.dispose();
if (node.material)
var materialArray;
if (node.material instanceof THREE.MeshFaceMaterial || node.material instanceof THREE.MultiMaterial)
materialArray = node.material.materials;
else if(node.material instanceof Array)
materialArray = node.material;
if(materialArray)
materialArray.forEach(function (mtrl, idx)
if (mtrl.map) mtrl.map.dispose();
if (mtrl.lightMap) mtrl.lightMap.dispose();
if (mtrl.bumpMap) mtrl.bumpMap.dispose();
if (mtrl.normalMap) mtrl.normalMap.dispose();
if (mtrl.specularMap) mtrl.specularMap.dispose();
if (mtrl.envMap) mtrl.envMap.dispose();
mtrl.dispose();
);
else
if (node.material.map) node.material.map.dispose();
if (node.material.lightMap) node.material.lightMap.dispose();
if (node.material.bumpMap) node.material.bumpMap.dispose();
if (node.material.normalMap) node.material.normalMap.dispose();
if (node.material.specularMap) node.material.specularMap.dispose();
if (node.material.envMap) node.material.envMap.dispose();
node.material.dispose();
);
【讨论】:
以上是关于Three.js Collada - dispose() 和释放内存(垃圾收集)的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
在 Three.JS 中通过鼠标单击选择 Collada 对象
Three.js - 从文件输入加载 Collada 文件(和纹理)