2017-05-08 73 views
0

为了用WebGL渲染许多精灵,我想我会问一些关于性能的问题。预先计算CPU上的顶点

让我们来看看这个:

for(let i = 0; i < 50000; i++){ 
    let t = new Sprite(); 
    t.scale(Math.random()) 
    t.rotate(Math.random()) 
    t.transform(Math.random(),Math.random()) 

随着scalerotatetransform

translate(x, y) { 
    for (let i = 0; i < this.vertexData.length; i += 3) { 
     this.vertexData[i] += x; 
     this.vertexData[i + 1] += y; 
    } 
    } 


    rotate(alpha) { 
    this.translate(-this.position[0], -this.position[1]); 
    for (let i = 0; i < this.vertexData.length; i += 3) { 
     let new_x = this.vertexData[i] * Math.cos(alpha) - this.vertexData[i + 1] * Math.sin(alpha); 
     let new_y = this.vertexData[i + 1] * Math.cos(alpha) + this.vertexData[i] * Math.sin(alpha); 
     this.vertexData[i] = new_x; 
     this.vertexData[i + 1] = new_y; 
    } 
    this.translate(this.position[0], this.position[1]); 
    } 


    scale(factor) { 
    this.translate(-this.position[0], -this.position[1]); 
    for (let i = 0; i < this.vertexData.length; i += 3) { 
     this.vertexData[i] *= factor; 
     this.vertexData[i + 1] *= factor; 
    } 
    this.translate(this.position[0], this.position[1]) 
    } 

而且this.vertexData=[-1, -1, 0, 1, -1, 0, -1, 1, 0, -1, 1, 0, 1, -1, 0, 1, 1, 0];

什么是我的可能性,使功能scalerotate及以下功能transform更快?要么依赖于语言,要么数学。

回答

1
  1. 将所有精灵的所有精灵数据放在一个数组中。 AFAICT你每个精灵使用一个数组。这意味着你必须分别为每个精灵的vertexData调用gl.bufferData。这比只使用一次上传所有精灵上传所有精灵数据的调用要慢。

    如果你仍想保留每个精灵一个对象,你可以有每个精灵使用的偏移量更大的全球阵列

    const maxSprites = 50000; 
    const globalVertData = new Float32Array(maxSprites * 12); 
    const quad = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]; 
    const numSprites = 0; 
    
    class Sprite { 
        constructor() { 
        const offset = numSprites++ * 12 * 4; 
        // make vertexData a view into the larger array 
        this.vertexData = new Float32Array(
         globalVertData.buffer, offset, 12); 
        this.vertexData.set(quad); 
        } 
        ... your functions from above ... 
    } 
    

    或本

    const maxSprites = 50000; 
    const globalVertData = new Float32Array(maxSprites * 12); 
    const quad = [-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]; 
    const numSprites = 0; 
    
    class Sprite { 
        constructor() { 
        this.offset = numSprites++ * 12; 
        globalVertData.set(quad, this.offset); 
        } 
        translate(x, y) { 
        let i = this.offset; 
        const end = i + 12; 
        for (; i < end; i += 2) { 
         globalVertData[i] += x; 
         globalVertData[i + 1] += y; 
        } 
        } 
        ... functions for rotate and scale that use this.offset ... 
    } 
    

    然后你只需上传globalVertDatagl.bufferData而不是每个精灵的vertexData

    我有直觉,第二个比第一个快。它还需要更少的内存,因为每个spite只有一个数组对象,而不是一个数组视图。这就是说我没有测试它,所以我可能是错的。

  2. 摆脱Z。假设你不需要Z的精灵摆脱它(它看起来你不会因为既不旋转也不翻译操纵z)。然后你上传的数据少了,至少scale会变得更快。我在上面做了这个。

  3. 从你的循环

    for (let i = 0; i < someArray.length; ++i) { 
        ... 
    

    拉出长度比慢

    const len = someArray.length; 
    for (let i = 0; i < len; ++i) { 
        ... 
    

    这也是慢

    const spriteLen = 12; // GLOBAL OR CLOSED VARIABLE 
    
    const len = spriteLen; 
    for (let i = 0; i < len; ++i) { 
        ... 
    

    基本上.运营商需要时间为array.lengthfoo.bar。 在第一个示例中,.运算符在每次迭代中都会发生。在 秒内,每个循环发生一次。在第三次它根本不会发生。

  4. let慢于var

    let creates a new object every iteration of the loop. Var does not但如果你将其拉出循环的这个问题会消失。有可能浏览器会在将来修复这个问题,他们可以分析代码,并且看到他们不需要在每次迭代时创建一个新对象(Spidermonkey似乎这样做,Chrome 60似乎也修复了这个问题。慢)

  5. 其他东西,通常有助于精灵。使用texture atlas。这样你就可以用一个平局调用画出所有精灵。

您可能会发现this answer以及有用

+0

谢谢您的回答,你闯民宅的问题实际上是我的问题!这个概念对我有很大的帮助,但很难找到合适的oop架构:) – greedsin

+0

但是这给我留下了一个问题。我将如何更新特定的精灵。我需要全局顶点数据中的精灵顶点数据的偏移量吗? – greedsin

+0

上述两个例子都处理这种情况。一个例子使用'ArrayBufferViews',这样每个精灵都可以查看更大的数组。另一个只使用偏移量。正如它在答案中所说,我怀疑偏移版本更快。这两种解决方案都是oop。 – gman