The mode argument decides how vertices v0, v1, ... become primitives: POINTS alone; LINES in pairs; LINE_STRIP joined in sequence, and LINE_LOOP closed back to v0; TRIANGLES in threes; TRIANGLE_STRIP each new vertex with the previous two; TRIANGLE_FAN with the previous one and v0. Here six zigzag vertices are drawn in all seven modes, in that order (four panels on top), each in its own viewport, with flat shading giving each primitive its last vertex's color:
<canvas id="c" width="720" height="230" style="width:720px;height:230px"></canvas>
<script src="webgl-helper.js"></script>
<script>
const gl = GLH.context('c', [1, 1, 1, 1]);
const vs = `#version 300 es
flat out vec3 vColor;
void main() {
float i = float(gl_VertexID); // zigzag: even vertices low, odd high
gl_Position = vec4(-0.75 + 0.3 * i, mod(i, 2.0) == 0.0 ? -0.6 : 0.6, 0.0, 1.0);
gl_PointSize = 10.0;
vColor = vec3[6](vec3(0.12, 0.37, 0.55), vec3(0.36, 0.25, 0.6), vec3(0.88, 0.6, 0.06),
vec3(0.25, 0.49, 0.23), vec3(0.71, 0.27, 0.18), vec3(0.16, 0.62, 0.56))[gl_VertexID];
}`, fs = `#version 300 es
precision lowp float; flat in vec3 vColor; out vec4 c; void main() { c = vec4(vColor, 1); }`;
['POINTS', 'LINES', 'LINE_STRIP', 'LINE_LOOP', 'TRIANGLES', 'TRIANGLE_STRIP', 'TRIANGLE_FAN']
.forEach((mode, k) => {
gl.viewport((k % 4) * 180 + 10, k < 4 ? 120 : 5, 160, 105);
GLH.load(gl, vs, fs); // a fresh program per mode: see below
gl.drawArrays(gl[mode], 0, 6);
});
window.__done = true;
</script>
The fresh program per mode dodges a bug met while making this figure: on Chrome 154 1 's Direct3D 11 backend, a program with flat varyings reused across line and triangle modes drew triangles as lines. Lines are 1 pixel wide (ALIASED_LINE_WIDTH_RANGE is [1, 1] here), so thick lines are built from triangles.
<!doctype html>
<style>
body { margin: 0; font: 11px system-ui, sans-serif; background: #f7f4ee; color: #333; }
.wrap { position: relative; width: 100%; max-width: 600px; }
canvas { display: block; width: 100%; background: #fff; }
.lbl { position: absolute; font-family: monospace; color: #555; }
</style>
<div class="wrap"><canvas id="c" width="600" height="240"></canvas></div>
<script>
const gl = document.getElementById('c').getContext('webgl2');
gl.clearColor(1, 1, 1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
const vs = `#version 300 es
flat out vec3 vColor;
void main() {
float i = float(gl_VertexID); // zigzag: even vertices low, odd high
gl_Position = vec4(-0.75 + 0.3 * i, mod(i, 2.0) == 0.0 ? -0.6 : 0.6, 0.0, 1.0);
gl_PointSize = 8.0;
vColor = vec3[6](vec3(0.12, 0.37, 0.55), vec3(0.36, 0.25, 0.6), vec3(0.88, 0.6, 0.06),
vec3(0.25, 0.49, 0.23), vec3(0.71, 0.27, 0.18), vec3(0.16, 0.62, 0.56))[gl_VertexID];
}`, fs = `#version 300 es
precision lowp float; flat in vec3 vColor; out vec4 c; void main() { c = vec4(vColor, 1); }`;
function load() {
const program = gl.createProgram();
for (const [type, src] of [[gl.VERTEX_SHADER, vs], [gl.FRAGMENT_SHADER, fs]]) {
const s = gl.createShader(type);
gl.shaderSource(s, src); gl.compileShader(s);
gl.attachShader(program, s);
}
gl.linkProgram(program);
gl.useProgram(program);
}
gl.bindVertexArray(gl.createVertexArray()); // no buffers: positions come from gl_VertexID
const wrap = document.querySelector('.wrap');
['POINTS', 'LINES', 'LINE_STRIP', 'LINE_LOOP', 'TRIANGLES', 'TRIANGLE_STRIP', 'TRIANGLE_FAN']
.forEach((mode, k) => {
const x = (k % 4) * 150 + 5, y = k < 4 ? 125 : 5;
gl.viewport(x, y, 140, 95);
load(); // a fresh program per mode (works around a flat-varying driver bug)
gl.drawArrays(gl[mode], 0, 6);
wrap.insertAdjacentHTML('beforeend',
`<div class="lbl" style="left:${x / 6}%;top:${(240 - y - 95 - 16) / 2.4}%">${mode}</div>`);
});
</script>