three.js性能研究——第一篇

≯℡__Kan透↙ 提交于 2019-12-15 22:50:31

现在开源的webgl引擎中,three.js是功能最丰富的,而且社区活跃,使用简单,但是它的性能确实不太理想。本系列就和大家一一探究three.js的性能到底如何,原因是什么,以及有什么改进方案。
首先我们模拟一个理论上性能最好的使用场景,scene下创建10000个sphere,每个sphere大概1000个顶点(测试显卡为mac Radeon Pro 555X 4 GB,相当于GTX1050左右)
代码如下:

var geometry =  new THREE.SphereBufferGeometry( 5, 32, 32 );
var material = new THREE.MeshBasicMaterial({transparent:false, color:new THREE.Color(1,0,0)});
 for ( var i = 0; i < 8000; i ++ ) {
            var mesh = new THREE.Mesh( geometry, material );
            mesh.position.x = Math.random() * 1600 - 800;
            mesh.position.y = 0;
            mesh.position.z = Math.random() * 1600 - 800;
            mesh.updateMatrix();
            mesh.matrixAutoUpdate = false;
            scene.add( mesh );
        }  

我们公用同一个材质,公用同一个geometry,不产生多余的节点,关掉scene的autoUpdate,使用basic材质,排除灯光的影响(理论上应该是three.js最佳的性能),下面看看帧率:
在这里插入图片描述
帧率也只不过31帧左右,这个性能也差不多是webgl的性能了,10000次drawCall,每次大概1000个顶点点物体差不多是这个帧率。
但是真实情况下,我们很难共用同一个材质,也很难共用同一个geometry,模拟三个不同的材质,帧率掉了5帧(如果是同一个材质对象,shader相同,three.js会有优化,掉帧可以忽略不计,当然define不同相当于使用了不同材质):
在这里插入图片描述
我们分析一下为什么:

	if ( material.id !== _currentMaterialId ) {

				_currentMaterialId = material.id;

				refreshMaterial = true;

			}

首先,如果创建不同的材质对象,则refreshMaterial会一直是true,这样会让每个材质的uniform全部上传,由于three.js没有实现uniformBlock(webgl2),因此这个开销也是有个2-3帧的差距的,当然如果我创建的是不同材质,除了uniform要更新外还要切shader,这样的开销更大,创建3个不同材质会导致5帧的开销。
如果材质公用,geometry每次创建一个新的对象:这样直接掉了7帧,这个帧率的开销非常大
在这里插入图片描述
我们看看为什么,

	var updateBuffers = false;

		if ( _currentGeometryProgram.geometry !== geometry.id ||
			_currentGeometryProgram.program !== program.id ||
			_currentGeometryProgram.wireframe !== ( material.wireframe === true ) ) {

			_currentGeometryProgram.geometry = geometry.id;
			_currentGeometryProgram.program = program.id;
			_currentGeometryProgram.wireframe = material.wireframe === true;
			updateBuffers = true;

		}

我们发现只要geometry的id不一样,则就会执行updateBuffers,创建attribute的buffer,然后上传,这个开销确实是巨大的,不仅影响显存,而且影响帧率,所以需要尽量能使用同一个geometry对象。
真实情况下,geometry很多不能公用,材质也有多个的情况,只有18帧了,掉了13帧 :
在这里插入图片描述
所以如果要绘制超过10000个物体,必须使用merge或者instancedMesh,下面是使用merge后的结果(满帧,instanced的性能和merge基本能差不多,而且能节省很多显存的开销,所以能使用instance尽量使用)
在这里插入图片描述

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!