Simple finishing of three.js (webgl) model deletion / scene clearing / memory release
content
Simple finishing of three.js (webgl) model deletion / scene clearing / memory release
Second, the realization principle
3. Model group (mesh) in the scene
4. Clear the scene scene and release the memory
1. Brief introduction
Some knowledge developed by Three js is convenient to encounter similar problems in the later period, and can be consulted and used in time.
This section introduces the three.js (webgl) model deletion / scene clearing / memory release simple sorting, for everyone to optimize the direction of thinking, if there are shortcomings, welcome to point out, or you have a better method, Welcome to leave a message.
When developing Web3D applications through Threejs, you may need to delete model objects in the scene. If you want to delete a 3D model object from a scene
Scene
or group objectGroup
, not only.remove()
, remember to delete it when necessary·dispose()
.When developing a 3D scene, if you need to dynamically add, delete, or modify models and scenes, or when pages are switched and re-rendered, in order to avoid memory overlapping, you need to manually clear the memory occupied by the scene to avoid overflow and waste of resources.
Second, the realization principle
1. For general models, remember to dispose() the geometry and material, and remove() the model mesh.
2. Clear the scene scene and release the memory, the key is as follows
- Use dispose() to clear the vertex buffer memory usage of all mesh geometry
- Use object.clear() to destroy the model object and clear the page memory
- Pause the requestAnimationFrame() method to avoid meaningless execution
- Empty the canvas canvas, empty the dom and related elements
3. Model group (mesh) in the scene
Scene
1. Delete a sub-object in the scene object Group
and release Group
the memory occupied by the vertex buffers of all mesh model geometry in the group object
deleteObject(group) {
// 递归遍历组对象group释放所有后代网格模型绑定几何体占用内存
group.traverse(function(obj) {
if (obj.type === 'Mesh') {
obj.geometry.dispose();
obj.material.dispose();
}
})
// 删除场景对象scene的子对象group
scene.remove(group);
}
2, another method, clear the Group
clearGroup(group) {
// 释放 几何体 和 材质
const clearCache = (item) => {
item.geometry.dispose();
item.material.dispose();
};
// 递归释放物体下的 几何体 和 材质
const removeObj = (obj) => {
let arr = obj.children.filter((x) => x);
arr.forEach((item) => {
if (item.children.length) {
removeObj(item);
} else {
clearCache(item);
item.clear();
}
});
obj.clear();
arr = null;
};
// 移除 group
removeObj(group);
}
记得:
1)如果是场景中
scene.remove(group); // 删除组
2)如果是 组中
groups.remove(group);// 删除模型
4. Clear the scene scene and release the memory
// 清空场景,包括 scene 场景下的动画,子物体,renderer,camera,control,以及自己使用过的变量置空处理 等
clearScene() {
cancelAnimationFrame(this.animationId);
this.scene.traverse((child) => {
if (child.material) {
child.material.dispose();
}
if (child.geometry) {
child.geometry.dispose();
}
child = null;
});
// 场景中的参数释放清理或者置空等
this.sceneDomElement.innerHTML = '';
this.renderer.forceContextLoss();
this.renderer.dispose();
this.scene.clear();
this.flows = [];
this.scene = null;
this.camera = null;
this.controls = null;
this.renderer.domElement = null;
this.renderer = null;
this.sceneDomElement = null;
console.log('clearScene');
}
5. Reference supplement: Three.js memory release problem (if it is not handled correctly, it may not be released, and it will occupy memory)
Reference blog post: Three.js memory release problem
1. The conventional method cannot completely remove some geometry, texture, etc. in the scene scene, and even if the page leaves, the memory will not be automatically released. Open the task manager, you may see that the CPU is always occupied, and it is getting higher and higher when switching pages.
//注意: 这里释放场景,并未处理必要的scene子物体的 geometry 、material 等
beforeDestroy() {
try {
scene.clear();
renderer.dispose();
renderer.forceContextLoss();
renderer.content = null;
cancelAnimationFrame(animationID) // 去除animationFrame
let gl = renderer.domElement.getContext("webgl");
gl && gl.getExtension("WEBGL_lose_context").loseContext();
}catch (e) {
console.log(e)
}
}
2. A track method is encapsulated here to manage the release of mesh, geometry, texture, object3D, externally loaded obj models, gltf models, etc. in the release scene
1) TrackResource method:
import * as THREE from 'three/build/three.module'
export default class ResourceTracker {
constructor() {
this.resources = new Set();
}
track(resource) {
if (!resource) {
return resource;
}
// handle children and when material is an array of materials or
// uniform is array of textures
if (Array.isArray(resource)) {
resource.forEach(resource => this.track(resource));
return resource;
}
if (resource.dispose || resource instanceof THREE.Object3D) {
this.resources.add(resource);
}
if (resource instanceof THREE.Object3D) {
this.track(resource.geometry);
this.track(resource.material);
this.track(resource.children);
} else if (resource instanceof THREE.Material) {
// We have to check if there are any textures on the material
for (const value of Object.values(resource)) {
if (value instanceof THREE.Texture) {
this.track(value);
}
}
// We also have to check if any uniforms reference textures or arrays of textures
if (resource.uniforms) {
for (const value of Object.values(resource.uniforms)) {
if (value) {
const uniformValue = value.value;
if (uniformValue instanceof THREE.Texture ||
Array.isArray(uniformValue)) {
this.track(uniformValue);
}
}
}
}
}
return resource;
}
untrack(resource) {
this.resources.delete(resource);
}
dispose() {
for (const resource of this.resources) {
if (resource instanceof THREE.Object3D) {
if (resource.parent) {
resource.parent.remove(resource);
}
}
if (resource.dispose) {
resource.dispose();
}
}
this.resources.clear();
}
}
2) Introduce track and initialize
import ResourceTracker from "../../../common/3D/dispose";
// 在外层定义resMgr和track
let resMgr = new ResourceTracker();
const track = resMgr.track.bind(resMgr);
3) Call the track method for all mesh, geometry, texture, object3D, externally loaded obj models, gltf models and other objects that need to be added to scene
let xxx = track(new Three.Vector3());
obj.geometry.computeBoundingBox();
obj.geometry.boundingBox.getCenter(center);
let wrapper = track(new Three.Object3D());
wrapper.position.set(center.x,center.y,center.z);
obj.position.set(-center.x,-center.y,-center.z);
wrapper.add(obj);
scene.add(wrapper);
return warpper;
4) Release the memory of the tracked 3D object
beforeDestroy() {
try {
scene.clear();
resMgr && resMgr.dispose()
renderer.dispose();
renderer.forceContextLoss();
renderer.content = null;
cancelAnimationFrame(animationID)
let gl = renderer.domElement.getContext("webgl");
gl && gl.getExtension("WEBGL_lose_context").loseContext();
console.log(renderer.info) //查看memery字段即可
}catch (e) {
console.log(e)
}
}