What is common cause of range out of bounds of buffer in WebGL
There are only 3 reasons you'd get that error when calling gl.drawElements
Your indices are referencing vertices out of range of your buffers
For example you make a buffer and put 3 position values in it
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);
Since there are only 3 positions the only possible indices are 0, 1, and 2. So if you put ANY OTHER VALUE in your index buffer you'll get that error.
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);
You tried to draw too many indices or set the offset out of range
Given the setup above if you did
gl.drawElements(gl.TRIANGLE, 4, gl.UNSIGNED_SHORT, 0);
You'd get out of range because you only put 3 indices in but you're asking to draw 4. Similarly if you change the offset
gl.drawElements(gl.TRIANGLE, 3, gl.UNSIGNED_SHORT, 1);
Again you only put 3 indices in but you're asking it to draw index 1,2, and 3 instead of 0, 1, and 2.
You set your attributes to access too much data
Let's assume we put in three 3 value positions like above. If we set the attribute to pull out three 4 value positions like this
var size = 4; // ERROR! There are only 3 value per position gl.vertexAttribPointer(location, size, gl.FLOAT, false, 0, 0);
That setup will try to access 12 floats of data (assuming your indices are correct) but you only put in 9 floats of data. size should equal 3
You can similarly mess up if you set the stride or the offset (the last 2 parameters to
gl.vertexAtrribPointer
to the wrong values. Nearly all WebGL programs always use 0, 0 there. If you're doing something more fancy make sure you set them correctly.
It's possible you may not be passing your array as the correct type. It's easy to forget to cast your vertices or indices from a general Javascript array to an explicitly typed array.
For example (adapted from gman's first example):
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);
In Javascript, every numeric value is represented by default as an object of type Number, which is an IEEE 64-bit float under the hood. So, for example, the first element of the indices
array, 3
, is represented by these 64 bits:
0000 0000 0001 1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
If you pass the regular Javascript array into the element array buffer, then when gl.drawElements()
asks to interpret the buffer as unsigned shorts (16-bit ints), then it instead sees those first 64 bits as 4 groups of 16 bits, and reads out the following values:
0000 0000 0001 1000 = 24
0000 0000 0000 0000 = 0
0000 0000 0000 0000 = 0
0000 0000 0000 0000 = 0
And of course 24 is out of range for our 4-element vertex position array buffer.