WebGL中范围超出缓冲区范围的常见原因是什么

时间:2015-09-08 00:38:22

标签: webgl

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

我确实确保通过了正确的缓冲区长度或偏移量。但是,仍然出现错误。

我认为有几个原因会导致错误。因此,我想问你的项目是否有同样的问题,你检查了什么来解决这个问题?

3 个答案:

答案 0 :(得分: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。如果您正在做更多的事情花哨确保你正确设置它们。

答案 1 :(得分:4)

您可能无法将数组作为正确的类型传递。很容易忘记将顶点或索引从一般Javascript数组转换为an explicitly typed array

例如(改编自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中,every numeric value is represented by default as an object of type 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元素顶点位置数组缓冲区的范围。

答案 2 :(得分:0)

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

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

代替:

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

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