Three.js Collada - dispose() 和释放内存(垃圾收集)的正确方法是什么?
Three.js Collada - What's the proper way to dispose() and release memory (garbage collection)?
我已经通过 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();
}
这应该可以完成工作:
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);
我调整了 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
}
}
}
});
}
根据此处的答案,此代码处理材料数组。
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();
}
}
}
});
}
经过网络研究和几次重构后,我得出以下结论:
disposeNode = ( node, recursive = false ) => {
if ( !node ) return;
if ( recursive && node.children)
for ( const child of node.children )
disposeNode( child , recursive );
node.geometry && node.geometry.dispose();
if ( !node.material ) return;
const materials = node.material.length === undefined ? [ node.material ] : node.material
for ( const material of materials ) {
for ( const key in material ) {
const value = material[key];
if ( value && typeof value === 'object' && 'minFilter' in value )
value.dispose();
}
material && material.dispose();
}
}
我已经通过 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();
}
这应该可以完成工作:
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);
我调整了 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
}
}
}
});
}
根据此处的答案,此代码处理材料数组。
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();
}
}
}
});
}
经过网络研究和几次重构后,我得出以下结论:
disposeNode = ( node, recursive = false ) => {
if ( !node ) return;
if ( recursive && node.children)
for ( const child of node.children )
disposeNode( child , recursive );
node.geometry && node.geometry.dispose();
if ( !node.material ) return;
const materials = node.material.length === undefined ? [ node.material ] : node.material
for ( const material of materials ) {
for ( const key in material ) {
const value = material[key];
if ( value && typeof value === 'object' && 'minFilter' in value )
value.dispose();
}
material && material.dispose();
}
}