Pure GPU, instanced, screen-projected lines for regl
This module implements a very general command for drawing lines using the regl WebGL library.
Architecturally this module has two goals:
- Data may live on the GPU.
- Minimize unnecessary constraints.
To accomplish this, it implements a simple pragma-based interface for specifying how your attributes connect to line properties and to varyings.
Features:
- Configure your own attributes, varyings, uniforms, and shaders
- Compute position and line width in the vertex shader
- GPU computation of round joins, bevels, and miters (with miter limit), and square and rounded end caps.
- Optional end cap insertion, using
position.w == 0.0
or alternativelyposition.x
NaN to signal a line break (see: docs/multiple.html) - Regl-compatible attribute specification with strides and offsets
- Forward additional regl configuration to the draw command
- Seamlessly permits substitution of Vertex Array Objects (VAOs)
- 13.4 KB minified, 5.3 KB gzipped. No dependencies (although it is expected to be used together with regl, which requirement I'd like to consider removing)
Limitations:
ANGLE_instanced_arrays
extension is required (which ought to be universally supported)- Width is best varied slowly as line joins to not take into account varying width
- Automatic end cap insertion wastes vertices when the cap resolution exceeds the join resolution
- Line dashes are not built-in, but you can easily build them yourself
The dist/
directory contains UMD bundles, or you may use from a CDN, e.g. https://unpkg.com/regl-gpu-lines@latest. Both expose the module as reglLines
.
Otherwise install from npm:
npm install regl-gpu-lines
See API documentation.
- Basic example: A minimal example. Just a line.
- Variable width: A basic line with variable width and color
- Multiple lines: Use position NaN to break up lines into multiple segments
- Depth: Layer lines using the z-coordinate
- Closed loop: Create a closed loop by omitting end caps and repeating the first three vertices at the end.
- Line border: Use
lineCoord
to draw a SDF line border - Interleaved attributes: Instead of a regl buffer, you can pass a regl-style attribute description with
buffer
,stride
,offset
, anddivisor
properties in order to used interleaved, packed attribute data. - Torus knot: A torus knot with layering which can be difficult to draw with SVG.
- Batched rendering: Illustrates how to take advantage of
reorder: true
to reduce shader program changes from, in this example, thirty to four. - Post-projection: Illustrates post-project to draw lines projected onto a plane from some other angle.
- Vertex Array Object (VAO): Illustrates seamless swapping of VAO for vertex and endpoint attributes.
- Fake instancing: Sort of allows you to mimic instanced rendering on top of instanced rendering, albeit with some duplication of data.
- Debug page: Shows how to use
instanceID
andtriStripCoord
varyings to draw a wireframe - Full debug view: A page for exploring all the bells and whistles
- GPGPU Strange Attractors: Feed a GPU particle simulation from texture data directly into line rendering
A minimal example looks like the following, where a vec2
attribute xy
is connected to line position via a GLSL #pragma
.
const drawLines = reglLines(regl, {
vert: `
precision highp float;
#pragma lines: attribute vec2 xy;
#pragma lines: position = getPosition(xy);
vec4 getPosition(vec2 xy) { return vec4(xy, 0, 1); }
#pragma lines: width = getWidth();
uniform float width;
float getWidth() { return width; }`,
frag: `
precision lowp float;
void main () {
gl_FragColor = vec4(1);
}`,
uniforms: {
width: (ctx, props) => props.customWidth * ctx.pixelRatio
}
});
const xy = [[-1, 1], [-0.5, -1], [0, 1], [0.5, -1], [1, 1]];
const lineData = {
customWidth: 20,
join: 'round',
cap: 'round',
vertexCount: xy.length,
vertexAttributes: {
xy: regl.buffer(xy)
},
endpointCount: 2,
endpointAttributes: {
xy: regl.buffer([xy.slice(0, 3), xy.slice(-3).reverse()])
}
};
drawLines(lineData);
Serve example pages—e.g. the example in examples/closed-loop.js
—with
npm start closed-loop
Run live-reloading render tests with
npm run serve-render-tests
Executing the render tests from the CLI requires the headless-gl module. You may use nodemon to live-run the render tests when the code is changed.
npm install -g nodemon
nodemon test/render.js
Filter tests with
FILTER=miter/basic nodemon test/render.js
and update expectation images with
UPDATE=1 FILTER=miter/basic node test/render.js
You may view the tests, run against the latest version from unpkg.com, at https://rreusser.github.io/regl-gpu-lines/docs/tests.html
- regl-line2d: The line rendering library used by Plotly.js. If you want production quality lines, you should go here.
- regl-line: A regl function to draw flat 2D and 3D lines.
- regl-insta-lines: A very clear and well-written module. Very close to what I was searching for. My main desire was to defer more of the configuration to runtime and to avoid overlap in the miters.
- screen-projected-lines: An excellent, concise module for screen-projected lines. Without joins or caps, such lines are much simpler.
- Drawing Lines is Hard: Matt DesLaurier's classic post on the topic of drawing lines.
- Instanced Line Rendering Part I: Rye Terrell first blog post on the topic.
- Instanced Line Rendering Part II: Alpha blending: Rye Terrell's blog post which inspired me to pare the draw calls down to two and publish this module.
© 2021 Ricky Reusser. MIT License.