介绍
我最近写了关于我使用three.js在应用程序中清理内存的经验。让我提醒您,目标是使用gltf模型重绘几个场景。
从那时起,我进行了许多实验,我认为有必要用这篇小文章来补充我之前所说的内容。以下几点可帮助我提高应用程序的性能。
主要部分
通过研究Three.js上的各种垃圾收集示例,我对threejsfundamentals.org上提出的方法感兴趣。但是,在实现建议的配置并将所有材料和几何图形包装在this.track()中之后,事实证明,加载新场景时,GPU上的负载继续增长。而且,由于无法在这些类中使用track(),因此所提出的示例无法与EffectComposer以及其他用于后期处理的类一起正常工作。
由于显而易见的原因,在所有使用的类中添加ResourceTracker的解决方案并不吸引人,因此,我决定补充用于清理提到的类的方法。以下是一些已使用的技术:
接待1.粗糙
在cleanup方法之后添加renderer.info。我们逐一从应用程序中删除资源,以了解它们中的哪些构成了负载并隐藏在纹理或材质中。这不是解决问题的方法,而只是调试某人可能不知道的方法。
接待2.长
打开所用类的代码(例如AfterimagePass,可在three.js github上找到)后,我们查看在何处创建需要清理的资源,以在所需框架内保持几何形状和材料的数量。
this.textureComp = new WebGLRenderTarget( window.innerWidth, window.innerHeight, { ... }
那就是你所需要的。根据文档,WebGLRenderTarget具有清除功能以清除内存。我们得到类似:
class Scene {
//...
postprocessing_init(){ //
this.afterimagePass = new AfterimagePass(0);
this.composer.addPass(this.afterimagePass);
}
//...
}
//...
class ResourceTracker {
//...
dispose() {
//...
sceneObject.afterimagePass.WebGLRenderTarget.dispose();
//...
}
}
接待3
可以,但是在这种情况下清理代码会变得肿。让我们尝试使用上一篇文章中我们熟悉的方法。让我提醒您,在其中我们实现了disposeNode(节点)方法,该方法在资源中搜索可以清除的内容。disposeNode()可能看起来像这样:
disposeNode(node) {
node.parent = undefined;
if (node.geometry) {
node.geometry.dispose();
}
let material = node.material;
if (material) {
if (material.map) {
material.map.dispose();
}
if (material.lightMap) {
material.lightMap.dispose();
}
if (material.bumpMap) {
material.bumpMap.dispose();
}
if (material.normalMap) {
material.normalMap.dispose();
}
if (material.specularMap) {
material.specularMap.dispose();
}
if (material.envMap) {
material.envMap.dispose();
}
material.dispose();
}
} else if (node.constructor.name === "Object3D") {
node.parent.remove(node);
node.parent = undefined;
}
}
太好了,现在让我们使用所有使用的其他类并将其添加到ResourceTracker中:
dispose() {
for (let key in sceneObject.afterimagePass) {
this.disposeNode(sceneObject.afterimagePass[key]);
}
for (let key in sceneObject.bloomPass) {
this.disposeNode(sceneObject.bloomPass[key]);
}
for (let key in sceneObject.composer) {
this.disposeNode(sceneObject.composer[key]);
}
}
结果
所有这些操作的结果是,我大大提高了FPS并减少了应用程序中的GPU负载。我可能没有正确使用ResourceTracker,但无论如何对其他类都无济于事。我从未见过任何地方通过我们的disposeNode(节点)在EffectComposer上进行迭代会影响内存中的纹理数量(但实际上是这种情况)。此问题应分开考虑。
为了进行比较,以前的版本将保留在旧地址,而新版本则可以单独查看。
该项目以某种形式出现在github上。
我很高兴听到您在类似项目中的经验并讨论细节!