Performance Three.js-精灵/文本标签性能
有一个包含一些3D对象和200-300个小文本标签的three.js场景(<10%在一个透视图上对摄影机可见)。添加文本精灵可以将FPS从60降低到30-40,而且还非常消耗内存 有没有办法让精灵跑得更快? 我读过关于缓存材料的文章,但是标签都是唯一的,所以这是不可能的 测试: (您可以更改SPRITE_计数以查看机器上的FPS下降) 编辑1:将画布大小设置为文本边界将减少内存消耗,但不会提高FPSPerformance Three.js-精灵/文本标签性能,performance,three.js,textures,sprite,Performance,Three.js,Textures,Sprite,有一个包含一些3D对象和200-300个小文本标签的three.js场景(
var Test = {
SPRITE_COUNT : 700,
init : function() {
this.renderer = new THREE.WebGLRenderer({antialias : true}); // false, a bit faster without antialias
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.container = document.getElementById('display');
this.container.appendChild(this.renderer.domElement);
this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
this.scene = new THREE.Scene();
this.group = new THREE.Object3D();
this.scene.add(this.group);
for (var i = 0; i < this.SPRITE_COUNT; i++) {
var sprite = this.makeTextSprite('label ' + i, 24);
sprite.position.set(Math.random() * 20 - 10, Math.random() * 20 - 10, Math.random() * 20 - 10);
this.group.add(sprite);
}
this.stats = new Stats();
this.stats.domElement.style.position = 'absolute';
this.stats.domElement.style.left = '0px';
this.stats.domElement.style.top = '0px';
document.body.appendChild(this.stats.domElement);
this.render();
},
render : function() {
var self = this;
this.camera.rotation.x += 0.002;
this.renderer.render(this.scene, this.camera);
this.stats.update();
requestAnimationFrame(function() {self.render();});
},
makeTextSprite : function(message, fontsize) {
var ctx, texture, sprite, spriteMaterial,
canvas = document.createElement('canvas');
ctx = canvas.getContext('2d');
ctx.font = fontsize + "px Arial";
// setting canvas width/height before ctx draw, else canvas is empty
canvas.width = ctx.measureText(message).width;
canvas.height = fontsize * 2; // fontsize * 1.5
// after setting the canvas width/height we have to re-set font to apply!?! looks like ctx reset
ctx.font = fontsize + "px Arial";
ctx.fillStyle = "rgba(255,0,0,1)";
ctx.fillText(message, 0, fontsize);
texture = new THREE.Texture(canvas);
texture.minFilter = THREE.LinearFilter; // NearestFilter;
texture.needsUpdate = true;
spriteMaterial = new THREE.SpriteMaterial({map : texture});
sprite = new THREE.Sprite(spriteMaterial);
return sprite;
}
};
window.onload = function() {Test.init();};
var测试={
雪碧计数:700,
init:function(){
this.renderer=new THREE.WebGLRenderer({antialias:true});//false,在没有antialias的情况下会快一点
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(window.innerWidth、window.innerHeight);
this.container=document.getElementById('display');
this.container.appendChild(this.renderer.doElement);
this.camera=新的3.PerspectiveCamera(45,window.innerWidth/window.innerHeight,11000);
this.scene=新的三个.scene();
this.group=new THREE.Object3D();
this.scene.add(this.group);
对于(var i=0;i
你是对的,three.js确实导致GPU以这种方式使用大量纹理内存。请记住,发送到GPU的每个纹理都必须高到宽,因此为每个精灵制作一个画布将浪费大量内存
这里的一个挑战是three.js设计选择在纹理上有一组UV坐标
;即使将标签精灵组合到单个纹理贴图中,并且无需额外努力即可为每个材质创建.clone()
纹理,它仍会将每个纹理
发送到GPU,而无需共享内存。简言之,它目前没有文档记录的方法来告诉它这些纹理是相同的,并且您不能将每个材质
指向相同的纹理
,因为保存UV的不是材质
。讨论这个问题
我通过在一个或多个纹理贴图中组合精灵来解决这些问题。为此,我创建了一个“sprite纹理图集管理器”,它可以根据需要管理sprite纹理的分配,并且我将一个背包算法移植到JS,它可以帮助我(主要)用标签填充这些纹理贴图,这样就不会浪费太多内存
我已经在一个单独的库中提取了这方面的代码,在这里可以找到:有一个实例(它还没有使用sprite,但应该很容易添加)
幸运的是,虽然这还没有被记录下来,但我也发现在最近的版本中(至少r73,也许还有r72),通过确保纹理都具有相同的.uuid
值来强制纹理共享GPU内存是相当容易的。我的库确保利用了这一点,在我目前的测试中(使用2048x2048 sprite贴图;我只需要两个与我渲染的大小相同的贴图),这将GPU内存从未共享时的~2.6GB降低到共享时的~300-600MB。(2048px在仅放置单个标签时太大,而当贴图不共享时,减小纹理大小有很大帮助)
最后,根据您自己的回答,drawcalls和culling在r73中也是一个性能问题。不过,我从来没有遇到过这个问题,因为我已经通过对所有内容进行分组来批处理我的draw调用。你是对的,three.js确实导致GPU以这种方式使用大量纹理内存。请记住,发送到GPU的每个纹理都必须高到宽,因此为每个精灵制作一个画布将浪费大量内存 这里的一个挑战是three.js设计选择在
纹理上有一组UV坐标
;即使将标签精灵组合到单个纹理贴图中,并且无需额外努力即可为每个材质创建.clone()
纹理,它仍会将每个纹理
发送到GPU,而无需共享内存。简言之,它目前有
<script src="https://rawgit.com/mrdoob/three.js/dev/build/three.js"> </script>