Is updating the entire VBO on each frame the most

2019-05-07 13:27发布

Answers to my previous question suggested that I use a Vertex Buffer Object and merge my position data with my color data into a single array, which I have now done in this simple test case:

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

Pseudo code for every frame:

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();
}

I know there is no silver bullet, but for my goal of rendering a screen full of changing unique triangles, is this the most efficient way possible? Would using bufferSubData offer any benefit over bufferData?

When I tested this in an animation loop, I could update around 800 triangles per frame before framerate suffered. Is this the limit of what I can do when I want unique and changing triangles on every frame? I see people throwing around much larger numbers like 50k triangles - is that because they are able to cache their vertex array on the graphics card and don't need to change every vertex and color on every frame? When using the canvas api, I can draw 1500 differently colored and positioned rectangles before framerate dips - what am I doing wrong with my WebGL that the canvas api outperforms it?

1条回答
Luminary・发光体
2楼-- · 2019-05-07 14:20

I took a look at your code and you've got a good bit of inefficiency in your JavaScript. For example, this line which is executed repeatedly:

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

can be extremely inefficient: a naïve execution of your program takes O(n^2) time where n is the number of vertices, because each time that line runs it copies elements into a new array.

By changing it to the following, I got much improved performance on Firefox and Safari (Chrome doesn't seem to care, perhaps because it optimizes the copying away):

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

Better still would be to change getConvertedVerts so that it takes the array to push onto rather than creating and returning one.

However, the way your program should probably be written is to allocate a Float32Array once, and then write new values directly into it (pass the array and a starting index around) in each frame. Avoid creating new arrays, and especially avoid creating new Float32Arrays, every frame, much less every vertex.

I would also recommend that you get rid of the intermediate canvas-emulation steps (like constructing an rgba() color and then parsing it again) — there is no reason to have any string-manipulation at all in your code, though this isn't nearly as much of an issue as the algorithmic inefficiency above.

查看更多
登录 后发表回答