WebGL: vertex buffer optimization that changes values ​​and vertex counts every frame

I would like to implement a renderer with vertex buffers that will be updated on the application side in each frame. In addition, the number of vertices (i.e., the number of triangles) will also change each frame.

My approach was to pre-allocate the maximum needed once as a Float32Array, and then update only the values ​​that change, and update the buffer data using bufferSubData. Then draw the ones I want by sending the range from the index buffer.

As a minimal example, suppose I select vertex positions for two separate triangles in a Float32Array, and for this frame I just want to move and draw a second triangle. I would think what I would do:

arrPos[9] += 1.0; // move the X coordinates in the Float32Array arrPos[12] += 1.0; arrPos[15] += 1.0; gl.bindBuffer(gl.ARRAY_BUFFER, bufPos); // tell GL which buffer to use gl.bufferSubData( gl.ARRAY_BUFFER, 3 * 3 * 4, arrPos ); // update the vertices - ERROR // then just draw the 2nd traingle by sending its indices only gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufId); // tell GL which buffer to use gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 3 * 2); // draw just this range 

The problem is that bufferSubData throws an error: "GL ERROR: GL_INVALID_VALUE: glBufferSubData: out of range"

I tried this using offsets 3, 9, 12 for bufferSubData just for that, but they all give me the same error.

In another note: if I can ever get this work, it seems to me that if I want to draw a variable number of triangles for each frame when reusing this previously allocated Float32Array, I will need to update the values ​​in the END of the array, and not at the beginning, since I can only specify the offset, not the starting index, in bufferSubData. I hope someone tells me whether this approach can work or not, or if I am completely disconnected and should stop wasting my time.

+6
source share
2 answers

Well, I think I just realized what the problem is. I do not think you can specify a range of Float32Array for bufferSubData; instead, it should take an ENTIRE array. (A Float32Array, which is smaller than the buffer, can be used to update the range of the buffer.)

In other words, I think that a new Float32Array should be created EVERY TIME, the number of updated vertices varies. It seems ineffective to me, but I think it is. IMO, this difference should be better explained in OpenGL docs.

david van brink suggested using ArrayBufferView to create a Float32Array helper array, and from my initial testing, it seems to work. My previous code can be fixed simply:

 arrPos[9] += 1.0; // move the X coordinates in the Float32Array arrPos[12] += 1.0; arrPos[15] += 1.0; var arrView = arrPos.subarray(9); // specify a range of the Float32Array gl.bindBuffer(gl.ARRAY_BUFFER, bufPos); // tell GL which buffer to use gl.bufferSubData( gl.ARRAY_BUFFER, 3 * 3 * 4, arrView ); // update the vertices // then just draw the 2nd traingle by sending its indices only gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufId); // tell GL which buffer to use gl.drawElements(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 3 * 2); // draw just this range 
+3
source

The biggest problem is gl.bufferSubData( gl.ARRAY_BUFFER, 3 * 3 * 4, arrPos ); You are about to load the entire array at offset. which, of course, is too big. A post is server years, but it can help others.

You were probably looking for this option:

 var offset = 3 * 3 * 4; var count = 7 * 4; // x1, y1, z1, x2, y2, z2, x3 (arrPos[9] -> arrPos[15]) gl.bufferSubData(this.gl.ARRAY_BUFFER, offset, arrView, offset, count); 
0
source

Source: https://habr.com/ru/post/957778/


All Articles