three.js(webgl)モデルの削除/シーンのクリア/メモリ解放の簡単な仕上げ

three.js(webgl)モデルの削除/シーンのクリア/メモリ解放の簡単な仕上げ

コンテンツ

three.js(webgl)モデルの削除/シーンのクリア/メモリ解放の簡単な仕上げ

1.簡単な紹介

第二に、実現原理

3.シーン内のモデルグループ(メッシュ)

4.シーンシーンをクリアし、メモリを解放します

5.リファレンスサプリメント:Three.jsのメモリ解放の問題(正しく処理されていない場合、解放されない可能性があり、メモリを占有します)


1.簡単な紹介

Three jsによって開発されたいくつかの知識は、後の期間に同様の問題に遭遇するのに便利であり、時間内に参照して使用することができます。

このセクションでは、three.js(webgl)モデルの削除/シーンのクリア/メモリリリースの簡単な並べ替えを紹介します。誰もが思考の方向を最適化するために、欠点がある場合、指摘することを歓迎します。メッセージ。

Threejsを使用してWeb3Dアプリケーションを開発する場合、シーン内のモデルオブジェクトを削除する必要がある場合があります。シーンSceneまたはグループオブジェクトから3Dモデルオブジェクトを削除する場合は、必要に応じて削除することを忘れGroupないでください.remove()·dispose()

3Dシーンを開発するとき、モデルやシーンを動的に追加、削除、または変更する必要がある場合、またはページを切り替えて再レンダリングする場合、メモリの重複を避けるために、シーンが占めるメモリを手動でクリアする必要があります。オーバーフローやリソースの浪費を避けてください。

第二に、実現原理

1.一般的なモデルの場合、ジオメトリとマテリアルをdispose()し、モデルメッシュをremove()することを忘れないでください。

2.シーンシーンをクリアしてメモリを解放します。キーは次のとおりです。

  • dispose()を使用して、すべてのメッシュジオメトリの頂点バッファメモリ使用量をクリアします
  • object.clear()を使用して、モデルオブジェクトを破棄し、ページメモリをクリアします
  • 意味のない実行を避けるために、requestAnimationFrame()メソッドを一時停止します
  • キャンバスキャンバスを空にし、domと関連要素を空にします

3.シーン内のモデルグループ(メッシュ)

1.シーンオブジェクト内のSceneサブオブジェクトを削除し、グループオブジェクト内のすべてのメッシュモデルジオメトリの頂点バッファによって占有されていたメモリGroupを解放しますGroup

deleteObject(group) {
    // 递归遍历组对象group释放所有后代网格模型绑定几何体占用内存
    group.traverse(function(obj) {
        if (obj.type === 'Mesh') {
        obj.geometry.dispose();
        obj.material.dispose();
      }
    })

    // 删除场景对象scene的子对象group
    scene.remove(group);
}

2、別の方法、グループをクリアする

 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.シーンシーンをクリアし、メモリを解放します

 // 清空场景,包括 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.リファレンスサプリメント:Three.jsのメモリ解放の問題(正しく処理されていない場合、解放されない可能性があり、メモリを占有します)

参照ブログ投稿:Three.jsメモリリリースの問題

1.従来の方法では、シーンシーンの一部のジオメトリやテクスチャなどを完全に削除することはできず、ページが離れてもメモリは自動的に解放されません。タスクマネージャを開くと、CPUが常に占有されており、ページを切り替えるときにCPUがどんどん高くなっていることがわかります。

//注意: 这里释放场景,并未处理必要的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.トラックメソッドがここにカプセル化され、リリースシーンでのメッシュ、ジオメトリ、テクスチャ、object3D、外部からロードされたobjモデル、gltfモデルなどのリリースを管理します。

1)TrackResourceメソッド:

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)トラックを導入して初期化します

	import ResourceTracker from "../../../common/3D/dispose";
	// 在外层定义resMgr和track
	let resMgr = new ResourceTracker();
	const track = resMgr.track.bind(resMgr);

3)シーンに追加する必要のあるすべてのメッシュ、ジオメトリ、テクスチャ、object3D、外部からロードされたobjモデル、gltfモデル、およびその他のオブジェクトに対してtrackメソッドを呼び出します。

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)追跡された3Dオブジェクトのメモリを解放します

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)
	}
}

おすすめ

転載: blog.csdn.net/u014361280/article/details/124309410