【问题标题】:WebGL: Optimizing a vertex buffer that changes values & vertex count every frameWebGL:优化每帧更改值和顶点计数的顶点缓冲区
【发布时间】:2013-11-10 16:20:37
【问题描述】:

我想实现一个带有顶点缓冲区的渲染器,每帧都会在应用程序端更新。此外,顶点的数量(即三角形的数量)也会在每一帧发生变化。

我的方法是预先分配一次所需的最大值作为 Float32Array,然后仅更新更改的值,并使用 bufferSubData 更新缓冲区数据。然后通过从索引缓冲区发送一个范围来绘制我想要的那些。

作为一个最小的例子,假设我已经为 Float32Array 中的 2 个单独的三角形分配了位置顶点,对于这个帧,我只想移动并绘制第二个三角形。我想我会这样做:

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

问题是,bufferSubData 抛出错误:“GL ERROR :GL_INVALID_VALUE : glBufferSubData: out of range”

我已经尝试过使用 bufferSubData 的偏移量 3、9、12 来解决这个问题,但它们都给了我同样的错误。

另外一点:如果我能做到这一点,在我看来,如果我想在重新使用这个预先分配的 Float32Array 的同时每帧绘制可变数量的三角形,我需要更新这些值在数组的末尾,而不是开头,因为我只能指定 bufferSubData 的偏移量,而不是起始索引。我希望有人能告诉我这种方法是否可行,或者我是否完全偏离了轨道,应该停止浪费我的时间。

【问题讨论】:

  • ArrayBufferView 可能是这里缺少的技巧吗?我对缓冲区管理还不是很流利,但我很确定您可以重复使用缓冲区,并根据需要进行部分更新...感谢您提出这个问题,现在我想了解更多信息!
  • 啊哈!是的,这似乎有效!所以我们可以使用 Float32Array.subarray 方法来选择源数组范围,使用 bufferSubData 来指定目标替换范围。然后,我们需要创建每个帧的唯一“新”对象是 ArrayBufferView。非常感谢,我没有想到要研究 TypedArray 方法,doh。

标签: javascript opengl-es-2.0 webgl


【解决方案1】:

好的,我想我刚刚意识到问题所在。我认为您不能将 Float32Array 的范围指定为 bufferSubData;相反,它必须采用整个数组。 (小于缓冲区的 Float32Array 可用于更新缓冲区的范围。)

换句话说,我认为每次要更新的顶点数量发生变化时,都必须创建一个新的 Float32Array。这对我来说似乎非常低效,但我想这就是它的方式。 IMO 应该在 OpenGL 文档中更好地解释这种区别。

david van brink 建议使用 ArrayBufferView 创建 Float32Array 的子数组,从我最初的测试来看,它似乎有效。我之前的代码可以通过以下方式修复:

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

【讨论】:

    【解决方案2】:

    最大的问题是gl.bufferSubData( gl.ARRAY_BUFFER, 3 * 3 * 4, arrPos ); 您即将在偏移量上上传整个数组。这当然太大了。该帖子已有数年历史,但可能对其他人有所帮助。

    您可能正在寻找这个:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多