Simple finishing of three.js (webgl) model deletion / scene clearing / memory release

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

1. Brief introduction

Second, the realization principle

3. Model group (mesh) in the scene

4. Clear the scene scene and release the memory

5. Reference supplement: Three.js memory release problem (if it is not handled correctly, it may not be released, and it will occupy 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 Sceneor group object Group, 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

Scene1. Delete a sub-object in the scene object Groupand release Groupthe 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)
	}
}

Guess you like

Origin blog.csdn.net/u014361280/article/details/124309410