5.9 - Interleaved Buffers

When you play a video game, the game pauses when you go to a new level or a new scene and the screen often goes blank for a few seconds. What is the video game doing. Perhaps you could guess based on the previous lessons?

A GPU has limited memory. When you play a video game and you change to a new scene, the game must delete all of its current buffer objects, create new buffer objects and upload the model data needed to render the new scene into these buffer objects. Now you know!

Managing Buffer Objects

You have two options when uploading model data into buffer objects.

  • Create a separate buffer object for each type of data, as was done in the previous lessons. Each vertex shader attribute variable is linked to a unique buffer object.
  • Create a single buffer object for all data of a model and interleave the data.

You have already seen several examples of the first option. For simple scenes with only a few models, this approach is sufficient. When you want to create complex scenes with 100’s of models, interleaved data is the better approach.

Interleaved data puts all model data into a single 1-dimensional array and uploads the data to a single buffer object. When you link an attribute variable in your vertex shader to a buffer object you have to tell WebGL how to get to the specific data for that variable. This is done using the parameters of the gl.vertexAttribPointer function.

gl.vertexAttribPointer(uint index, int size, enum type, bool normalized, long stride, long offset);

The parameters have the following meaning:

  • index : the location of the attribute variable to link to.
  • size : the number of components in the attribute value; 1, 2, 3 or 4.
  • type : the data type of each component value; e.g., gl.FLOAT.
  • normalized : if true, integer values are normalized to -1.0 to + 1.0; For WebGL, always false.
  • stride : number of bytes between the start of one attribute value and the next attribute value.
  • offset : number of bytes to skip to get to the first value.

An example should make things clear. You have an (x,y,z) value for every vertex in your model, as well as a RGB color value, and an (s,t) texture coordinate value. All 8 values for every vertex will be stored sequentially in a 1D array. The data would look like this:

[x1,y1,z1, r1,g1,b1, s1,t1, x2,y2,z2, r2,g2,b2, s2,t2, x3,y3,z3, r3,g3,b3, s3,t3,...]

Let’s assume your vertex shader has the three attribute variables below that need to be linked to the single buffer object.

attribute vec3 a_vertex;
attribute vec3 a_color;
attribute vec2 a_texture;

You need to make the buffer object active and then call the gl.vertexAttribPointer function three times like this:

var buffer_data = new Float32Array(size);
bytes_per_float = buffer_data[0].BYTES_PER_ELEMENT;

gl.bindBuffer(gl.ARRAY_BUFFER, buffer_object_id);

gl.vertexAttribPointer(vertex_location,  3, gl.FLOAT, false, bytes_per_float*8, 0);
gl.vertexAttribPointer(color_location,   3, gl.FLOAT, false, bytes_per_float*8, bytes_per_float*3);
gl.vertexAttribPointer(texture_location, 2, gl.FLOAT, false, bytes_per_float*8, bytes_per_float*6);


interleaved data
store all attribute values for a model in a single 1D array. The WebGL graphics pipeline can access the correct values assuming it knows where the first value starts, and how many bytes from the start of one attribute value to the start of the next attribute value.
Next Section - 5.10 - Converting OBJ Model Data to Buffer Objects