2017-05-08 81 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