为什么 WebGL 不允许将相同的缓冲区绑定到 Array_Buffer 和 Element_Array_Buffer?

Why doesn't WebGL allow binding the same buffer to Array_Buffer and Element_Array_Buffer?

参考:https://github.com/tmpvar/WebGL-standalone/blob/master/test/khronos-tests/conformance/buffers/buffer-bind-test.html

为什么 WebGL 不允许将同一个缓冲区绑定到数组和索引目标?

因为 WebGL 需要安全,因为它 运行 在网络浏览器中,任何随机站点或广告都可以 运行 WebGL 代码。

为了安全起见,它必须检查所有使用都不会越界读取或写入任何数据。一个简单的输入示例是调用具有较大宽度和高度但缓冲区太小的 gl.texImage2D。正常的 C OpenGL 会愉快地读取缓冲区末尾,但 WebGL 不会并且会给出错误。一个简单的输出示例是调用 gl.readPixels 并为给定的宽度和高度设置一个较小的缓冲区。 OpenGL 会很高兴地丢弃缓冲区之外的内存。 WebGL 将生成一个错误。

因此,类似地,当您调用 gl.drawElements 时,您正在使用索引缓冲区访问其他缓冲区中的数据。如果这些索引中的任何一个太大,它们将访问越界数据。例如,您在具有 3 个顶点的属性上有一个缓冲区,但索引为 3。唯一在范围内的索引是 0、1 和 2。OpenGL 不关心这个但 WebGL 关心。

因此,为了确保您不能这样做,WebGL 必须验证您的索引。换句话说,它必须通读您的 ELEMENT_ARRAY_BUFFER 并检查没有索引会引用越界数据。为此,它必须在 ELEMENT_ARRAY_BUFFER 中保留一份数据副本(因为 OpenGL ES 2.0 无法提供从缓冲区读取数据的方法,即使这样做也太慢了)。 WebGL 缓冲区中的数据副本使用内存,因此为了不浪费内存,只有使用 ELEMENT_ARRAY_BUFFER 制作的缓冲区才会保留其数据副本。其他缓冲区不需要拥有其数据的副本。

由于这两种类型的缓冲区在 WebGL 中不兼容,因此您不能将一种缓冲区同时绑定到 ARRAY_BUFFERELEMENT_ARRAY_BUFFER。这样做将需要两种缓冲区来保留数据的副本。

注意:WebGL 实现将与独立游戏相关的信息缓存在 ELEMENT_ARRAY_BUFFER 中。这意味着您第一次使用给定范围的缓冲区进行绘制时,WebGL 将扫描数据副本以确保没有索引超出范围。下次您使用相同范围使用相同缓冲区绘制时,如果您没有更改缓冲区中的任何数据,则 WebGL 已经知道最高索引并且不必再次扫描缓冲区。