为什么我的简单webgl演示如此之慢

时间:2015-01-12 15:18:11

标签: javascript webgl

我一直在尝试使用these awesome tutorials来学习Web GL。我的目标是制作一个非常简单的2D游戏框架来取代基于画布的jawsJS。

我基本上只是希望能够创建一堆精灵并将它们移动,然后可能会在以后使用。

我整理了一个基本的演示,但是我遇到了一个我无法追踪的性能问题。一旦我到达屏幕上大约2000个精灵,帧速率坦克和我无法解决原因。与demo of the pixi.js webgl framework相比,它开始在约3万个兔子左右丢失帧数(在我的机器上),我有点失望。

My demoframework source)有5002个精灵,其中两个正在移动,帧速率在厕所里。

我已经尝试通过pixi.js框架来尝试找出他们做的不同的事情,但它是500kloc并且做得比我多得多,我无法解决它。

我发现this answer基本上证实了我所做的大致是正确的 - 我的算法与答案中的算法几乎相同,但必须有更多的算法。

到目前为止,我尝试了一些方法 - 只使用一个'帧缓冲区',定义了一个形状,然后为每个精灵翻译5000次。这确实有助于帧速率,但没有关闭pixi演示(它意味着所有精灵必须是相同的形状!)。我删除了所有不移动的矩阵数学,所以也不是这样。这一切似乎都归结为drawArrays()函数 - 它对我来说真的很慢,但仅限于我的演示!

我还尝试删除所有基于纹理的东西,用一个简单的块颜色替换片段着色器。它几乎没有任何区别,因此我将狡猾的纹理处理作为罪魁祸首。

我非常感谢能帮助我找到一些令人难以置信的愚蠢行为!

编辑:我肯定误解了一些关键点。我将整个事物剥离回基础,将顶点和片段着色器更改为超级简单:

attribute vec2 a_position;

void main() {
    gl_Position = vec4(a_position, 0, 1);
}

void main() {
    gl_FragColor = vec4(0,1,0,1);  // green
}

然后将精灵设置为绘制到(0,0),(1,1)。

使用5000个精灵,绘制一个帧需要大约5秒钟。这是怎么回事?

2 个答案:

答案 0 :(得分:4)

使用WebGLInspector或chrome中的实验canvas inspector查看帧调用会显示完全未优化的渲染循环。

您可以而且应该使用同一个顶点缓冲区渲染所有几何体, 这样您就可以保存bindBuffer以及vertexAttribPointer来电。 您还可以保存99%的纹理绑定,因为您可以重复使用相同的纹理重新绑定。只要您不将其他东西绑定到同一个纹理单元,纹理就会保持绑定。

拥有状态缓存有助于避免绑定已绑定的数据。

看看my answer here关于作为状态机的gpu。

一旦优化了渲染循环,您就可以继续考虑以下事项:

  • 使用ANGLE_instanced_arrays扩展
  • 避免在渲染循环中构建数据。
  • 使用隔行扫描顶点缓冲区。
  • 在某些情况下,使用索引缓冲区也会增加 性能
  • 检查是否可以在着色器中削减几个GPU周期
  • 将对象分解为块,并在CPU端查看视锥体剔除。

答案 1 :(得分:1)

问题可能在于渲染中的这一行:glixl.context.uniformMatrix3fv(glixl.matrix, false, this.matrix);

根据我的经验,在每个模型中传递制服在webGL中非常慢,并且在大约1,000个独特模型之后我无法维持60FPS。不幸的是,webgl中没有统一的缓冲区来缓解这个问题。

我通过计算CPU上的所有顶点位置并使用一个drawArray调用绘制所有顶点位置来解决我的问题。如果顶点数不是很大,这应该有效。我可以以60 FPS绘制2k移动+旋转立方体。我不记得你能以60 FPS绘制多少立方体,但它比2k高得多。如果这不够快,那么你必须调查drawArrayInstanced。基本上,将所有矩阵存储在数组缓冲区上,并使用正确偏移量的drawArrayInstanced调用绘制所有模型。

编辑:也是OP,如果你想看看PIXI如何进行顶点更新渲染(不是统一的实例化),请参阅https://github.com/GoodBoyDigital/pixi.js/blob/master/src/pixi/renderers/webgl/utils/WebGLFastSpriteBatch.js