1
votes

While trying to display a few objects of different shapes in webgl, I found only the latest created buffer to be used while rendering. This seems odd since I bind the current buffer before rendering every time:

gl.useProgram(this.program);
gl.enableVertexAttribArray(this.a_Position);
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);

gl.uniformMatrix4fv(this.u_ModelMatrix, false, MVPMatrix.elements);
gl.uniform4fv(this.u_FragColor, this.color);

gl.drawArrays(gl.TRIANGLES, 0, 6);
gl.disableVertexAttribArray(this.a_Position);
gl.bindBuffer(gl.ARRAY_BUFFER, null);

So to test the most basic example I tried to create two buffers after each other and see which one would be used:

var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(this.a_Position);
// gl.enableVertexAttribArray(this.a_UV);
gl.vertexAttribPointer(this.a_Position, 3, gl.FLOAT, false, 3*4, 0);
// gl.vertexAttribPointer(this.a_UV, 2, gl.FLOAT, false, 5*4, 3*4);
gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array([
         0.5,  0.5, 0,
        -0.5, -0.5, 0,
         0.5, -0.5, 0,
         0.5,  0.5, 0,
        -0.5,  0.5, 0,
        -0.5, -0.5, 0
    ]),
    gl.STATIC_DRAW
);
gl.bindBuffer(gl.ARRAY_BUFFER, null);

var buffer2 = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer2);
gl.enableVertexAttribArray(this.a_Position);
gl.vertexAttribPointer(this.a_Position, 3, gl.FLOAT, false, 3*4, 0);
gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array([
         1,  0.5, 0,
        -0, -0.5, 0,
         1, -0.5, 0,
         1,  0.5, 0,
        -0,  0.5, 0,
        -0, -0.5, 0
    ]),
   gl.STATIC_DRAW
);
this.buffer = buffer;

The result is that the latter buffer, (buffer2) is rendered every time. Why is that? What am I missing?

1

1 Answers

2
votes

Vertex attribute pointers are a global state not local to buffers and there is no need to setup vertex attribute pointers for when you set data to a buffer.

A vertexAttribPointer call basically tells the GPU "hey the positions start at 0 and are 3 floats each" and the GPU obeys by setting the attribute pointer to currently bound buffer address + attribute offset, however when you change the buffer this pointer remains untouched still pointing at that "old" buffer, you need to update it by another call to vertexAttribPointer.

So your buffer initialization code becomes:

var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array([
         0.5,  0.5, 0,
        -0.5, -0.5, 0,
         0.5, -0.5, 0,
         0.5,  0.5, 0,
        -0.5,  0.5, 0,
        -0.5, -0.5, 0
    ]),
    gl.STATIC_DRAW
);

In your render code you then set the vertex attribute pointers to the actively bound buffer:

gl.useProgram(this.program);
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);
gl.enableVertexAttribArray(this.a_Position);

// Set vertex attribute pointer to current buffer
// Note: I adjusted the stride to 0 to make sense
//       in the context of this question/answer
gl.vertexAttribPointer(this.a_Position, 3, gl.FLOAT, false, 0, 0);

gl.uniformMatrix4fv(this.u_ModelMatrix, false, MVPMatrix.elements);
gl.uniform4fv(this.u_FragColor, this.color);
gl.drawArrays(gl.TRIANGLES, 0, 6);