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



回答我之前的问题建议我使用顶点缓冲对象和合并我的位置数据与我的颜色数据到一个单一的数组,我现在已经在这个简单的测试用例:

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三角形——这是因为他们能够在显卡上缓存顶点数组,而不需要在每一帧上更改每个顶点和颜色吗?当使用画布api时,我可以在帧率下降之前绘制1500个不同颜色和位置的矩形-我的WebGL做错了什么,画布api优于它?

我看了一下你的代码,你的JavaScript效率很低。例如,重复执行的这一行:

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

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

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

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

更好的方法是改变getConvertedVerts,这样它就可以使用要压入的数组,而不是创建并返回一个数组。

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

我还建议您去掉中间的画布模拟步骤(比如构造一个rgba()颜色,然后再次解析它)——没有理由在您的代码中进行任何字符串操作,尽管这并不像上面的算法效率低下那么严重。

最新更新