1
votes

I'm still new to WebGL, and I'm trying to make a simple WebGL app using 2 different programs. In the initialization step, when I set the attributes of each shape's vertices, it turns out that the vertex attribute of the second program (red square) affects the first program (purple triangle) as well.

Here's what the first object (in the code called "shooter") is supposed to look like. The second program is not added yet:

enter image description here

And here's what it looks like after the second program (the "ball") is added.

enter image description here

Here is my code at the render stage. programs is a dictionary of programs, loc is of attribute locations, and buffers is of WebGL buffers. createProgram is a helper function that returns the WebGL program from GLSL code.

    // Shooter ============================
    programs.shooter = createProgram(gl,
        document.getElementById('shooter-vertex').textContent,
        document.getElementById('shooter-fragment').textContent);
    gl.useProgram(programs.shooter);

    loc.shooterVerts = gl.getAttribLocation(programs.shooter, 'aPosition');
    // (...color and uniform attribute stuff)

    buffers.shooterVerts = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.shooterVerts);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(geometry.shooter.shape), gl.STATIC_DRAW);
    gl.vertexAttribPointer(loc.shooterVerts, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(loc.shooterVerts);

    // Ball ================================
    programs.ball = createProgram(gl,
        document.getElementById('ball-vertex').textContent,
        document.getElementById('ball-fragment').textContent);
    gl.useProgram(programs.ball);

    loc.ballVerts = gl.getAttribLocation(programs.ball, 'aPosition');
    // (...uniform attributes)

    buffers.ballVerts = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.ballVerts);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(geometry.ball.shape), gl.STATIC_DRAW);
    gl.vertexAttribPointer(loc.ballVerts, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(loc.ballVerts);

At the render stage:

function render() {
    gl.clear(gl.COLOR_BUFFER_BIT);

    gl.useProgram(programs.shooter);
    // (...set some uniforms)

    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.shooterVerts);
    gl.drawArrays(gl.TRIANGLES, 0, geometry.shooter.shape.length / 2);

    gl.useProgram(programs.ball);
    // (...set another uniforms)
    gl.bindBuffer(gl.ARRAY_BUFFER, buffers.ballVerts);
    gl.drawArrays(gl.TRIANGLE_FAN, 0, geometry.ball.shape.length / 2);

    requestAnimationFrame(render);
}

Here is the complete code if anybody needs it: https://codepen.io/PseudoLW/pen/GRrwWeG

1

1 Answers

1
votes

The draw call (drawArrays) uses the current vertex specification to draw the object. The buffer object only stores the vertices, but binding the buffer has no effect on drawArrays. When the vertexAttribPointer is called, the buffer currently bound to the target ARRAY_BUFFER is associated to the specified vertex attribute. Therefore, you must specify the vertex attributes before you can draw the mesh:

// bind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.shooterVerts);
// specify the vertices and specify to use the current buffer (buffers.shooterVerts)
gl.vertexAttribPointer(loc.shooterVerts, 2, gl.FLOAT, false, 0, 0);
// draw the mesh
gl.drawArrays(gl.TRIANGLES, 0, geometry.shooter.shape.length / 2);
// bind the buffer
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.ballVerts);
// specify the vertices and specify to use the current buffer (buffers.ballVerts)
gl.vertexAttribPointer(loc.ballVerts, 2, gl.FLOAT, false, 0, 0);
// draw the mesh
gl.drawArrays(gl.TRIANGLE_FAN, 0, geometry.ball.shape.length / 2);

In WebGL 2.0, the vertex specification can be stored in a Vertex Array Object, but in WebGL 1.0, the vertices must be specified before the Draw call.