Reputation: 1650
I'm trying to use instancing with WebGL based on this guide. I've tried to create a simple example that draws a red triangle on the left and a blue triangle on the right. When I run it, it draws a blue triangle on the left and I don't understand why.
I've tried changing the arguments to drawArraysInstancedANGLE
but that doesn't help. I've tried changing the order of lines for binding buffers and setting attribute pointers, etc. What am I doing wrong? Thanks
const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl");
const ext = gl.getExtension("ANGLE_instanced_arrays");
const vert = gl.createShader(gl.VERTEX_SHADER);
const frag = gl.createShader(gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.shaderSource(vert, `
attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 v_color;
void main() {
gl_Position = a_position;
v_color = a_color;
}
`);
gl.shaderSource(frag, `
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
`);
gl.compileShader(vert);
gl.compileShader(frag);
gl.attachShader(program, vert);
gl.attachShader(program, frag);
gl.linkProgram(program);
const a_position = gl.getAttribLocation(program, "a_position");
const buffer1 = gl.createBuffer();
const positions = [-0.5, 0, -0.5, 0.2, -0.3, 0, 0.5, 0, 0.5, 0.2, 0.3, 0];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer1);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const a_color = gl.getAttribLocation(program, "a_color");
const buffer2 = gl.createBuffer();
const colors = [1, 0, 0, 1, 0, 0, 1, 1];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer2);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
gl.viewport(0, 0, 300, 300);
gl.useProgram(program);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer1);
gl.enableVertexAttribArray(a_position);
gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer2);
gl.enableVertexAttribArray(a_color);
gl.vertexAttribPointer(a_color, 4, gl.FLOAT, false, 0, 0);
ext.vertexAttribDivisorANGLE(a_color, 1);
ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 3, 2);
<canvas id="canvas" width="300" height="300"></canvas>
Upvotes: 0
Views: 247
Reputation:
So I see you mostly already got an answer in the comments.
The code is drawing the first triangle twice, once in red, then once in blue.
But, ... you mentioned indexing a uniform array. That would be unusual
Normally you'd put per instance data in a buffer. The example on the site linked used a matrix just to be generic since a matrix well will let you do just about any math (translation, rotation, scale, 3d projection, ...) but just as an example, you could just pass in single x offset.
const canvas = document.getElementById("canvas");
const gl = canvas.getContext("webgl");
const ext = gl.getExtension("ANGLE_instanced_arrays");
const vert = gl.createShader(gl.VERTEX_SHADER);
const frag = gl.createShader(gl.FRAGMENT_SHADER);
const program = gl.createProgram();
gl.shaderSource(vert, `
attribute vec4 a_position;
attribute float a_xoffset;
attribute vec4 a_color;
varying vec4 v_color;
void main() {
gl_Position = a_position;
gl_Position.x += a_xoffset;
v_color = a_color;
}
`);
gl.shaderSource(frag, `
precision mediump float;
varying vec4 v_color;
void main() {
gl_FragColor = v_color;
}
`);
gl.compileShader(vert);
gl.compileShader(frag);
gl.attachShader(program, vert);
gl.attachShader(program, frag);
gl.linkProgram(program);
const a_position = gl.getAttribLocation(program, "a_position");
const buffer1 = gl.createBuffer();
const positions = [-0.5, 0, -0.5, 0.2, -0.3, 0];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer1);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const a_color = gl.getAttribLocation(program, "a_color");
const buffer2 = gl.createBuffer();
const colors = [1, 0, 0, 1, 0, 0, 1, 1];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer2);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
const a_xoffset = gl.getAttribLocation(program, "a_xoffset");
const buffer3 = gl.createBuffer();
const xoffsets = [0, 1];
gl.bindBuffer(gl.ARRAY_BUFFER, buffer3);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(xoffsets), gl.STATIC_DRAW);
gl.viewport(0, 0, 300, 300);
gl.useProgram(program);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer1);
gl.enableVertexAttribArray(a_position);
gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer2);
gl.enableVertexAttribArray(a_color);
gl.vertexAttribPointer(a_color, 4, gl.FLOAT, false, 0, 0);
ext.vertexAttribDivisorANGLE(a_color, 1);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer3);
gl.enableVertexAttribArray(a_xoffset);
gl.vertexAttribPointer(a_xoffset, 1, gl.FLOAT, false, 0, 0);
ext.vertexAttribDivisorANGLE(a_xoffset, 1);
ext.drawArraysInstancedANGLE(gl.TRIANGLES, 0, 3, 2);
<canvas id="canvas" width="300" height="300"></canvas>
I'm just pointing that out because you have millions of values in a buffer but uniforms are far more limited so indexing a uniform for instancing is not common.
If you actually wanted different data per instance then yes you'd have to do something else.
One example is here
Upvotes: 1