【问题标题】:Three.js - Sprite / Text Label PerformanceThree.js - Sprite / 文本标签性能
【发布时间】:2016-01-15 15:51:51
【问题描述】:

有一个 three.js 场景,其中包含一些 3D 对象和 200 - 300 个小文本标签(

有没有办法让精灵更快? 我阅读了有关缓存材料的信息,但标签都是唯一的 - 所以这是不可能的。

测试:https://jsfiddle.net/h9sub275/4/ (您可以更改 SPRITE_COUNT 以查看您机器上的 FPS 下降)

编辑 1:将画布大小设置为文本边界将减少内存消耗,但不会提高 FPS。

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

【问题讨论】:

  • 如果我不得不冒险猜测,我会说 three.js 正在为每个精灵标签执行 1 个绘制调用。从性能的角度来看,最好将所有精灵标签一起批处理为一个批处理并通过一次调用进行绘制。

标签: performance three.js textures sprite


【解决方案1】:

你是对的,three.js 确实导致 GPU 以这种方式使用大量纹理内存。请记住,发送到 GPU 的每个纹理都必须与宽度一样高,因此为每个精灵制作单个画布会浪费大量内存。

这里的挑战是three.js 设计选择在Texture 上拥有一组UV 坐标;即使您将标签精灵组合在单个纹理贴图中并且您.clone() 为每种材质提供了您的纹理而不需要额外的努力,它仍然会将每个Texture 发送到 GPU 而不共享内存。简而言之,它目前没有记录的方式告诉它这些纹理是相同的,并且您不能将每个 Material 指向同一个 Texture,因为它不是保持 UV 的 Materialhttps://github.com/mrdoob/three.js/issues/5821 讨论了这个问题。

我通过将我的精灵组合到一个或多个纹理贴图中解决了这些问题。为此,我创建了一个“精灵纹理图集管理器”,它根据需要管理精灵纹理的分配,并且我将一个背包算法移植到 JS,它可以帮助我(大部分)用我的标签填充这些纹理贴图,所以不是很多内存被浪费了。

我已经在一个单独的库中提取了我的代码,它可以在这里找到:https://github.com/Leeft/three-sprite-texture-atlas-managerhttp://jsfiddle.net/Shiari/sbda72k9/ 有一个现场示例(尚未使用精灵,但应该很容易添加) .

幸运的是,虽然这还没有记录,但我还发现现在在最近的版本中(至少是 r73,也许还有 r72)很容易通过确保它们都具有相同的纹理来强制共享 GPU 内存.uuid 值。我的库确保利用这一点,并且在我迄今为止的测试中(使用 2048x2048 精灵图;我只需要我正在渲染的大小中的两个)这使得 GPU 内存在不共享时从 ~2.6GB 下降共享时约为 300-600MB。 (不过,当您只在其中放置一个标签时,2048px 太大了,而在不共享地图时减小纹理大小有很大帮助)。

最后,根据您自己的回答,绘制调用和剔除也是 r73 中的性能问题。不过我从来没有遇到过这个问题,因为我已经通过对所有内容进行分组来批处理我的绘图调用。

【讨论】:

  • 感谢您的建议!如果我有时间,我会尝试进一步改进。事实证明,three.js WebGLRenderer 中存在一个错误(缺少对精灵的视锥检查,请参阅下一个答案)顺便说一句:酷星图 :)
  • 当然可以。我在使我的代码成为一个单独的库方面取得了很大进展,这将使任何人都更容易构建纹理图集,我会在准备好时更新我的​​答案。就我个人而言,我总是批量处理我的标签精灵,GPU 内存一直是我的性能罪魁祸首(这对移动设备的影响比什么都大)。虽然也很高兴了解剔除问题。
  • 我已经更新了我的答案,因为我的库现在可用,如果你想使用它。希望有帮助!
【解决方案2】:

这是three.js WebGLRenderer 中的一个错误(在 问题及详情https://github.com/mrdoob/three.js/issues/7371

带有最新开发版本的固定版本:https://jsfiddle.net/h9sub275/9/
使用 r73 进行性能测试:https://jsfiddle.net/h9sub275/7/
(点击查看手动移除不可见精灵与不移除的性能差异)

最新的开发版本:

<script src="https://rawgit.com/mrdoob/three.js/dev/build/three.js"> </script>

【讨论】:

    猜你喜欢
    • 2014-06-24
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    • 1970-01-01
    相关资源
    最近更新 更多