作者:caven chen
对此系列感兴趣还可以看前文:
前言
WebGL 是一种强大的图形渲染技术,可以在浏览器中快速渲染复杂的 3D 场景。但是,由于 WebGL 的高性能和高质量要求,如果不注意性能优化,它可能会消耗大量的 CPU 和 GPU 资源,导致应用程序性能下降。
首先性能优化是一个比较大的话题,会涉及多个技术点,对于大场景来说,一般优化可以分为以下几个大的方向:
- 加载性能的优化
- 渲染帧率的优化
- 内存管理的优化
今天我们讨论就是第三个方向:内存管理的优化,内存管理的优化可以从以下方面入手
接下来的优化都是以threejs为示例的,对于其他的webgl框架,请选择同样功能的接口或者方法
浏览器的选择
在大场景的渲染下,我们要尽量引导客户使用 64 位的浏览器 chrome 或者 Firefox,这样可以最大限度的使用 js 内存,防止 V8 js Heap 爆了的情况。
Memory savings when browsing in Windows 10
释放BufferAttribute
对于模型数据,大量的顶点、法线等等 buffer 数据也是非常占用内存的。我们可以在 js 推送完数据之后,将这部分数据从内存中释放掉,从而降低 JS 的内存压力,如果使用 threejs 进行渲染,BufferAttribute包含一个onUpload回调函数,在数据推送到 GPU 之后调用。我们可以在回调函数中释放掉 js 中的数据。值得注意的是,这个回调函数只在第一次的时候有用,在 attribute 更新 update 的时候,并不会触发。
function disposeArray() {
this.array = null;
}
geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ).onUpload( disposeArray ) );
geometry.setAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ).onUpload( disposeArray ) );
geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colors, 4 ).onUpload( disposeArray ) );
释放材质
材质定义了物体将如何被渲染。three.js使用材质所定义的信息来构造一个着色器程序,以用于渲染。 着色器程序只有在相应材质被废置后才能被删除。由于性能的原因,three.js尽可能尝试复用已存在的着色器程序。 因此,着色器程序只有在所有相关材质被废置后才被删除。 你可以通过执行Material.dispose()方法来废置材质。
释放纹理
对材质的废置不会对纹理造成影响。它们是分离的,因此一个纹理可以同时被多个材质所使用。 每当你创建一个Texture实例的时候,three.js在内部会创建一个WebGLTexture实例。 和buffer相似,该对象只能通过调用Texture.dispose()来删除。
释放Geomertry
几何体常用来表示定义为属性集合的顶点信息,three.js在内部为每一个属性创建一个WebGLBuffer类型的对象。 这些实体仅有在调用BufferGeometry.dispose()的时候才会被删除。 如果应用程序中的几何体已废弃,请执行该方法以释放所有相关资源。
在threejs中释放材质、纹理、Geomertry基本是同时进行的,因此绝大部分情况我们只要执行以下代码就可以进行内存的释放
function dispose( object3D)
{
// Dispose children first
for ( let childIndex = 0; childIndex < object3D.children.length; ++childIndex )
{
this.dispose( object3D.children[childIndex] );
}
object3D.children = [];
if ( object3D instanceof THREE.Mesh )
{
// Geometry
object3D.geometry.dispose();
// Material(s)
if ( object3D.material instanceof THREE.MultiMaterial )
{
for ( let matIndex = 0; matIndex < object3D.material.materials.length; ++matIndex )
{
object3D.material.materials[matIndex].dispose();
object3D.material.materials[matIndex] = null;
}
object3D.material.materials = [];
}
if ( object3D.material.dispose )
{
object3D.material.dispose();
object3D.material = null;
}
}
// Remove from parent
if ( object3D.parent )
object3D.parent.remove( object3D );
object3D = null;
}
总结
通过本文相信你已了解了内存管理的优化方法,目前介绍的优化方式在实际开发过程中可以进行有机组合使用,这样更好的降低内存
参考:
https://zhuanlan.zhihu.com/p/154425898
关注Mapmost,持续更新GIS、三维美术、计算机技术干货
Mapmost是一套以三维地图和时空计算为特色的数字孪生底座平台,包含了空间数据管理工具(Studio)、应用开发工具(SDK)、应用创作工具(Alpha)。平台能力已覆盖城市时空数据的集成、多源数据资源的发布管理,以及数字孪生应用开发工具链,满足企业开发者用户快速搭建数字孪生场景的切实需求,助力实现行业领先。