我可以让模型渲染,我可以旋转,缩放,一切都很好UNTIL,我尝试清除场景。我想点击button#clear
清除场景。
我希望遍历场景,并将其子项添加到数组中。然后,我希望迭代数组,对于数组中的每个项目,如果它是几何体或材质,则通过调用dispose()
清除它,然后从场景中删除网格。
<html>
<head>
<title>Three.js</title>
<link rel="stylesheet" href="css/main.css" />
</head>
<body>
<button id="clear">Clear Three Out</button>
<script src="js/three.js"></script>
<script src="js/OrbitControls.js"></script>
<script src="js/ObjectLoader.js"></script>
<script>
<script>
(function(){var script=document.createElement('script');script.onload=function(){var stats=new Stats();document.body.appendChild(stats.dom);requestAnimationFrame(function loop(){stats.update();requestAnimationFrame(loop)});};script.src='//rawgit.com/mrdoob/stats.js/master/build/stats.min.js';document.head.appendChild(script);})();
var scene = new THREE.Scene();
var width = window.innerWidth;
var height = window.innerHeight;
var camera = new THREE.OrthographicCamera(width / - 2, width / 2, height / 2, height / - 2, -1000, 1000); // new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
var blackReflectiveMaterial = new THREE.MeshBasicMaterial();
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// handle resize event
window.addEventListener( 'resize', function() {
var width = window.innerWidth;
var height = window.innerHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
} );
// controls
controls = new THREE.OrbitControls( camera, renderer.domElement );
camera.position.z = 3;
// model loader
var loader = new THREE.ObjectLoader();
loader.load(
'models/revol-uv.json', // model of a compound bow
function( object ) {
console.log('object: ', object);
object.scale.x = object.scale.y = object.scale.z = 200;
object.traverse( function(child) {
child.material = blackReflectiveMaterial;
});
scene.add( object );
}
);
scene.translateY(-345);
// array to hold Scene's children
var holder = [];
// when click the #clear button, call this function
document.getElementById('clear').onclick = function() {
scene.traverse( function ( child ) {
if (child.type === "Mesh") {
holder.push(child);
}
} );
console.log('holder before clean: ', holder);
for (var i = 0; i < holder.length; i++) {
if (holder[i].geometry) {
holder[i].geometry.dispose();
}
console.log('holder[i].material: ', holder[i].material);
if (holder[i].material) {
if (holder[i].map) {
holder[i].material.map.dispose();
}
holder[i].material.dispose();
}
console.log('holder[i]: ', holder[i]);
scene.remove(holder[i]);
}
console.log('holder after clean: ', holder); // all the objects are still there
}
// logic
var update = function() {
// any code to rotate ... blah blah not important
};
// draw Scene
var render = function() {
renderer.render( scene, camera );
};
// run loop (update, render, repeat)
var bowLoop = function() {
requestAnimationFrame( bowLoop );
update();
render();
};
bowLoop();
</script>
</body>
</html>
这是控制台日志:
现场的孩子
Array(10)
0:THREE.Mesh {uuid: "5574129D-7093-4567-8927-4F07BB7A3928", name: "cable-arm", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
1:THREE.Mesh {uuid: "ED867F5C-F6C4-45BC-BBF7-9DD5061A0CF6", name: "cams", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
2:THREE.Mesh {uuid: "D69C58BB-1E03-4D00-8050-6F2F4739DFE9", name: "handles", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
3:THREE.Mesh {uuid: "50A98720-4E8F-4873-B987-0C993D05FE65", name: "hardware", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
4:THREE.Mesh {uuid: "6CE44421-0614-40E9-8013-FE939CFA0191", name: "limb-pockets", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
5:THREE.Mesh {uuid: "60FF4521-B19B-477D-8223-8B4BFA2A0F5A", name: "limbs", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
6:THREE.Mesh {uuid: "D2980C91-0B19-4757-A831-A3B46546E579", name: "limbsavers", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
7:THREE.Mesh {uuid: "D9858B1C-E4F7-40C4-98DD-163230F9A917", name: "riser", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
8:THREE.Mesh {uuid: "BC7C199B-2867-4446-86FE-D244D7A32E07", name: "string-supressor", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
9:THREE.Mesh {uuid: "02A038E9-FB0B-43FF-B3F2-BCCAFD7E10AC", name: "strings", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
清理前的持有人数组:
Array(10)
0:THREE.Mesh {uuid: "5574129D-7093-4567-8927-4F07BB7A3928", name: "cable-arm", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
1:THREE.Mesh {uuid: "ED867F5C-F6C4-45BC-BBF7-9DD5061A0CF6", name: "cams", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
2:THREE.Mesh {uuid: "D69C58BB-1E03-4D00-8050-6F2F4739DFE9", name: "handles", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
3:THREE.Mesh {uuid: "50A98720-4E8F-4873-B987-0C993D05FE65", name: "hardware", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
4:THREE.Mesh {uuid: "6CE44421-0614-40E9-8013-FE939CFA0191", name: "limb-pockets", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
5:THREE.Mesh {uuid: "60FF4521-B19B-477D-8223-8B4BFA2A0F5A", name: "limbs", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
6:THREE.Mesh {uuid: "D2980C91-0B19-4757-A831-A3B46546E579", name: "limbsavers", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
7:THREE.Mesh {uuid: "D9858B1C-E4F7-40C4-98DD-163230F9A917", name: "riser", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
8:THREE.Mesh {uuid: "BC7C199B-2867-4446-86FE-D244D7A32E07", name: "string-supressor", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
9:THREE.Mesh {uuid: "02A038E9-FB0B-43FF-B3F2-BCCAFD7E10AC", name: "strings", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
清理后的持有人数组:
Array(10)
0:THREE.Mesh {uuid: "5574129D-7093-4567-8927-4F07BB7A3928", name: "cable-arm", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
1:THREE.Mesh {uuid: "ED867F5C-F6C4-45BC-BBF7-9DD5061A0CF6", name: "cams", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
2:THREE.Mesh {uuid: "D69C58BB-1E03-4D00-8050-6F2F4739DFE9", name: "handles", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
3:THREE.Mesh {uuid: "50A98720-4E8F-4873-B987-0C993D05FE65", name: "hardware", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
4:THREE.Mesh {uuid: "6CE44421-0614-40E9-8013-FE939CFA0191", name: "limb-pockets", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
5:THREE.Mesh {uuid: "60FF4521-B19B-477D-8223-8B4BFA2A0F5A", name: "limbs", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
6:THREE.Mesh {uuid: "D2980C91-0B19-4757-A831-A3B46546E579", name: "limbsavers", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
7:THREE.Mesh {uuid: "D9858B1C-E4F7-40C4-98DD-163230F9A917", name: "riser", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
8:THREE.Mesh {uuid: "BC7C199B-2867-4446-86FE-D244D7A32E07", name: "string-supressor", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
9:THREE.Mesh {uuid: "02A038E9-FB0B-43FF-B3F2-BCCAFD7E10AC", name: "strings", type: "Mesh", parent: T…E.Scene, children: Array(0), …}
内存没有变化......对象仍在堆中。
答案 0 :(得分:1)
我想到了两件事:
看起来holder
在调用clear-function之后仍然保持对所有对象的引用(h / t @pailhead)。你应该在函数的末尾添加类似holder = [];
的东西来摆脱它们。还要确保没有其他可访问的变量包含对任何对象的引用。
请注意,对象不会自动从内存中消失,而是仅在垃圾收集器完成其工作后才会消失。取决于发生了多少,否则可能需要一些时间。
答案 1 :(得分:0)
@gaitat - 感谢您提供了大量的解决方案。
我需要修改一些行来满足我的需求:
function disposeNode(node) {
if (node instanceof THREE.Mesh) {
if (node.geometry) {
node.geometry.dispose();
node.geometry = undefined; // fixed problem
}
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();
mrtl = undefined; // fixed problem
} );
}
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();
node.material = undefined; // fixed problem
}
}
}
console.log('node before removal: ', node);
scene.remove( node );
renderer.dispose(); // ***EDIT*** improved even memory more original scene heap is 12.4 MB; add objects increases to 116 MB or 250 MB (different models), clearing always brings down to 13.3 MB ... there still might be some artifacts.
node = undefined; // unnecessary
}
function disposeHierchy(node, callback) {
for (var i = node.children.length - 1; i >= 0; i--) {
var child = node.children[i];
disposeHierchy(child, callback);
callback(child);
}
}
称之为:
document.getElementById('clear').onclick = function() {
disposeHierchy(scene, disposeNode);
console.log('renderer.info.memory after: ', renderer.info);
}
答案 2 :(得分:0)
请检查以下代码以加载 GLTF 文件并释放内存...
let ZomModel = undefined;
function loadZoom() {
const gltfLoader = new GLTFLoader();
gltfLoader.load(modelName, (gltf) => {
const root = gltf.scene;
setmaterial(root);
ZomModel = root;
root.position.set(0, -3, 0);
root.scale.set(5, 5, 5);
scene.add(root);
console.log(root, 'root')
});
}
function loadNew(isLoad) {
console.log("reload " + isLoad);
// return;
if (isLoad) {
if (ZomModel == undefined)
loadZoom();
} else {
// defultmaterial(ZomModel);
if (ZomModel == undefined) return;
ZomModel.traverse(object => {
if (!object.isMesh) return
scene.remove(object);
console.log('dispose geometry!')
object.geometry.dispose()
if (object.material.isMaterial) {
cleanMaterial(object.material)
} else {
// an array of materials
for (const material of object.material) cleanMaterial(material)
}
object.geometry = undefined;
object = undefined;
});
scene.remove(ZomModel);
ZomModel = undefined;
}
}
const cleanMaterial = material => {
console.log('dispose material!')
// dispose textures
for (const key of Object.keys(material)) {
const value = material[key]
if (value && typeof value === 'object' && 'minFilter' in value) {
console.log('dispose texture! ' + key)
value.dispose();
}
}
material.dispose();
material = undefined;
}