I'm trying to learn how to draw basic thick 2D lines in WebGL2, with the help of instancing and normals.
I'm trying to follow the instructions here, the very first example that begins with "Basic instanced line rendering". But I'm doing it without Regl.
Basic components:
- position attribute - a basic shape (two triangles), identical for every instance
- pointA and pointB attributes - the line endpoints, changes between instances
- width uniform - half the width should be added on each side of the line
For the sake of simplicity, I have removed the projection matrix and some other components that I believe are not strictly needed.
I have a feeling I'm missing something obvious, because I'm not getting any results on the screen. I have gone over the calculation in the vertex shader, the coordinates, offsets, strides, etc, but not been able to find the issue. Maybe I just don't understand instancing very well. It's quite difficult to troubleshoot when you don't get any error messages.
Any help would be appreciated.
// Shaders
const vertexShaderSrc = `
precision highp float;
uniform float width;
attribute vec2 position;
attribute vec2 pointA;
attribute vec2 pointB;
void main() {
vec2 xBasis = pointB - pointA;
vec2 yBasis = normalize(vec2(-xBasis.y, xBasis.x));
vec2 point = pointA + xBasis * position.x + yBasis * width * position.y;
gl_Position = vec4(point, 0, 1);
}`;
const fragmentShaderSrc = `
precision highp float;
void main() {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}`;
// Setup program with shaders
const gl = document.qetElementById('canvas').getContext('webgl2');
const program = gl.createProgram();
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSrc);
gl.compileShader(vertexShader);
gl.attachShader(program, vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSrc);
gl.compileShader(fragmentShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.log(gl.getShaderInfoLog(vertexShader));
console.log(gl.getShaderInfoLog(fragmentShader));
}
gl.useProgram(program);
// Geometry:
const geometryData = new Float32Array([
// Triangle 1
0, -0.5,
1, -0.5,
1, 0.5,
// Triangle 2
0, -0.5,
1, 0.5,
0, 0.5
]);
// End points:
const pointsData = new Float32Array([
// pointA pointB
-0.2,0.7, 0.3,-0.5,
0.3,-0.5, -0.2,0.7,
]);
// Setup data for rendering:
function main() {
const positionLoc = gl.getAttribLocation(program, 'position');
const pointALoc = gl.getUniformLocation(program, 'pointA');
const pointBLoc = gl.getUniformLocation(program, 'pointB');
const widthLoc = gl.getUniformLocation(program, 'width');
const geometryBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, geometryBuffer);
gl.bufferData(gl.ARRAY_BUFFER, geometryData, gl.STATIC_DRAW);
gl.vertexAttribPointer(
positionLoc, // attribute
2, // size
gl.FLOAT, // type
false, // normalize
16, // stride
0); // offset
gl.vertexAttribDivisor(positionLoc, 0);
gl.enableVertexAttribArray(positionLoc);
const pointsBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, pointsBuffer);
gl.bufferData(gl.ARRAY_BUFFER, pointsData, gl.STATIC_DRAW);
gl.vertexAttribPointer(
pointALoc, // attribute
2, // size
gl.FLOAT, // type
false, // normalize
16, // stride
0); // offset
gl.vertexAttribPointer(
pointBLoc, // attribute
2, // size
gl.FLOAT, // type
false, // normalize
16, // stride
8); // offset
gl.vertexAttribDivisor(pointALoc, 1);
gl.vertexAttribDivisor(pointBLoc, 1);
gl.enableVertexAttribArray(pointALoc);
gl.enableVertexAttribArray(pointBLoc);
gl.uniform1f(widthLoc, 4) // line thickness
gl.drawArraysInstanced(
gl.TRIANGLES, // method
0, // offset
6, // number of vertices per instance
2); // number of instances
}
main();