WebGL 中缓冲区越界的常见原因是什么

问题描述 投票:0回答:3

我正在参与一个webgl项目。 当我调用 gl.DrawElements 时,显示错误“范围超出缓冲区范围”。

我确实确保传递了正确的缓冲区长度或偏移量。但是,仍然显示错误。

我认为有几个原因可能会引发错误。因此,我想问一下您的项目中是否遇到了同样的问题,您检查了什么来解决这个问题?

webgl
3个回答
14
投票

您在调用

gl.drawElements

时收到该错误的原因只有 3 个
  1. 您的索引引用的顶点超出了缓冲区范围

    例如,你创建一个缓冲区并在其中放入 3 个位置值

    var buf = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buf);
    var data = [1,2,3,4,5,6,7,8,9]; // 3 (3 value) positions
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
    

    由于只有 3 个位置,唯一可能的索引是 0、1 和 2。因此,如果您在索引缓冲区中放入任何其他值,您将收到该错误。

    var indexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buf);
    var indices = [0,1,3]; // ERROR! That 3 is out of range
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
    
    // This will generate an out of bounds error because
    // the 3 index we put in the index buffer is out of range
    // as the only valid indices are 0, 1, and 2.
    gl.drawElements(gl.TRIANGLE, 3, gl.UNSIGNED_SHORT, 0);
    
  2. 您尝试绘制太多索引或设置偏移量超出范围

    如果您这样做了,请按照上面的设置

    gl.drawElements(gl.TRIANGLE, 4, gl.UNSIGNED_SHORT, 0); 
    

    你会超出范围,因为你只输入了 3 个索引,但你要求绘制 4 个。同样,如果你更改偏移量

    gl.drawElements(gl.TRIANGLE, 3, gl.UNSIGNED_SHORT, 1);
    

    您只输入了 3 个索引,但要求它绘制索引 1,2 和 3,而不是 0、1 和 2。

  3. 您设置的属性访问了太多数据

    假设我们像上面一样放入了三个 3 值位置。如果我们将属性设置为像这样拉出三个4值位置

    var size = 4; // ERROR! There are only 3 value per position
    gl.vertexAttribPointer(location, size, gl.FLOAT, false, 0, 0);
    

    该设置将尝试访问 12 个浮点数据(假设您的索引正确),但您只输入了 9 个浮点数据。大小应等于 3

    如果您将步幅或偏移量(最后 2 个参数

    gl.vertexAtrribPointer
    )设置为错误的值,您也会同样陷入混乱。几乎所有 WebGL 程序总是在那里使用 0, 0。如果您正在做一些更奇特的事情,请确保您正确设置它们。


5
投票

您可能没有将数组作为正确的类型传递。 人们很容易忘记将顶点或索引从一般的 Javascript 数组转换为显式类型数组

例如(改编自 gman 的第一个示例):

var buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
var data = [1,2,3,  4,5,6,  7,8,9,  10,11,12];  // 4 3-D positions
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
//                             ^^^^^^^^^^^^^^^^
// Failure to explicitly construct a typed array here can give this WebGL error,
// if you bind this array to an attribute:
//   GL_INVALID_OPERATION : glDrawElements: attempt to access out of range vertices in attribute 0

var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buf);
var indices = [3,2,1];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
//                                     ^^^^^^^^^^^^^^^
// Failure to explicitly construct a typed array here gives this WebGL error:
//   GL_INVALID_OPERATION : glDrawElements: range out of bounds for buffer

gl.drawElements(gl.TRIANGLE, 3, gl.UNSIGNED_SHORT, 0);

在 Javascript 中,默认情况下每个数值都表示为 Number 类型的对象,它是一个 IEEE 64 位浮点数。 因此,例如,

indices
数组的第一个元素
3
由这64位表示:

0000 0000 0001 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

如果将常规 Javascript 数组传递到元素数组缓冲区中,那么当

gl.drawElements()
要求将缓冲区解释为无符号短整型(16 位整数)时,它会将前 64 位视为 4 组 16 位,并且读出以下值:

0000 0000 0001 1000  =  24
0000 0000 0000 0000  =   0
0000 0000 0000 0000  =   0
0000 0000 0000 0000  =   0

当然,24 超出了我们的 4 元素顶点位置数组缓冲区的范围。


0
投票

出现此错误是因为我正在使用:

gl.drawElements(drawingMode, count, this.gl.UNSIGNED_INT, 0)

而不是:

gl.drawElements(drawingMode, count, this.gl.UNSIGNED_SHORT, 0)

(当然,加载的数据是 Uint16Array 而不是 Uint32Array)。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.