在每一帧上更新整个 VBO 是绘制许多变化的独特三角形的最有效方法吗?

Posted

技术标签:

【中文标题】在每一帧上更新整个 VBO 是绘制许多变化的独特三角形的最有效方法吗?【英文标题】:Is updating the entire VBO on each frame the most efficient way to draw many changing unique triangles? 【发布时间】:2014-07-07 17:54:59 【问题描述】:

对my previous question 的回答建议我使用顶点缓冲区对象并将我的位置数据与我的颜色数据合并到一个数组中,我现在已经在这个简单的测试用例中完成了:

http://jsfiddle.net/headchem/r28mm/14/

每一帧的伪代码:

function drawFrame() 
    // clear global vertex[] array containing both position and color
    // recreate it with new triangles and colors (determined elsewhere)
    drawShapes();

    // put the vertex array into the VBO using gl.bufferData
    // finish with a single call to gl.drawArrays(gl.TRIANGLES, 0, numItems);
    render();

我知道没有灵丹妙药,但对于我的目标是渲染一个充满变化的独特三角形的屏幕,这是最有效的方法吗?使用 bufferSubData 会比 bufferData 有什么好处吗?

当我在动画循环中对此进行测试时,我可以在帧速率受到影响之前每帧更新大约 800 个三角形。当我想要在每一帧上都有独特的和不断变化的三角形时,我能做的就是这个限制吗?我看到人们扔出更大的数字,比如 50k 三角形 - 是因为他们能够在显卡上缓存顶点数组并且不需要更改每一帧上的每个顶点和颜色?使用 canvas api 时,我可以在帧率下降之前绘制 1500 个不同颜色和定位的矩形 - 我的 WebGL 做错了什么,canvas api 的性能优于它?

【问题讨论】:

【参考方案1】:

我查看了您的代码,发现您的 javascript 效率很低。例如,重复执行的这一行:

convertedVerts = convertedVerts.concat(getConvertedVerts(pxVerts, zIndex, color));

可能效率极低:天真的执行程序需要 O(n^2) 时间,其中 n 是顶点数,因为每次运行该行时,它都会将元素复制到一个新数组中。

通过将其更改为以下内容,我在 Firefox 和 Safari 上的性能得到了很大提升(Chrome 似乎并不在意,也许是因为它优化了复制操作):

convertedVerts.push.apply(convertedVerts, getConvertedVerts(pxVerts, zIndex, color));

最好还是更改getConvertedVerts,以便将数组推送到而不是创建和返回一个。

然而,你的程序可能应该被编写的方式是分配一个Float32Array一次,然后在每一帧中直接向其中写入新值(传递数组和起始索引) .避免创建新数组,尤其是避免每帧创建新的Float32Arrays,更不用说每个顶点了。

我还建议您摆脱中间的画布仿真步骤(例如构造一个 rgba() 颜色然后再次解析它)——尽管如此,您的代码中根本没有任何理由进行任何字符串操作这几乎没有上述算法效率低下的问题那么严重。

【讨论】:

哇!我实施了您的所有建议 (jsfiddle.net/headchem/r28mm/16),三角形计数变得疯狂。现在我的笔记本电脑可以在帧速率减慢之前绘制 100,000 个三角形。我错误地认为我的问题出在 WebGL 中。感谢您向我展示这些 javascript 优化!

以上是关于在每一帧上更新整个 VBO 是绘制许多变化的独特三角形的最有效方法吗?的主要内容,如果未能解决你的问题,请参考以下文章

我的 Android 应用程序正在耗尽电池电量吗?

脚本-流程

更新 VBO 还是使用制服?

VBO 与即时模式性能

进入下一帧/错误时如何停止循环声音

Open GL:多线程 glFlushMappedBufferRange?