A set of five demos with animated WebGL lines created with the THREE.MeshLine library. Find out how to animate and build these lines to create your own animations.

Two years ago, I started playing with lines in WebGL using THREE.MeshLine, a library made by Jaume Sanchez Elias for Three.js.

This library tackles the problem that you cannot handle the width of your lines with classic lines in Three.js. A MeshLine builds a strip of triangles billboarded to create a custom geometry instead of using the native WebGL GL_LINE method that does not support the width parameter.

These lines shaped as ribbons have a really interesting graphic style. They also have less vertices than a TubeGeometry usually used to create thick lines.

Animate a MeshLine

The only thing missing is the ability to animate lines without having to rebuild the geometry for each frame.

Based on what had already been started and how SVG Line animation works, I added three new parameters to MeshLineMaterial to visualize animated dashed line directly through the shader.

DashRatio: The ratio between what is visible or not ( ~0 : more visible, ~1 : less visible)

The ratio between what is visible or not ( : more visible, : less visible) DashArray: The length of a dash and its space (0 == no dash)

The length of a dash and its space (0 == no dash) DashOffset: The location where the first dash begins

Like with an SVG path, these parameters allow you to animate the entire traced line if they are correctly handled.

Here is a complete example of how to create and animate a MeshLine:

// Build an array of points const segmentLength = 1; const nbrOfPoints = 10; const points = []; for (let i = 0; i < nbrOfPoints; i++) { points.push(i * segmentLength, 0, 0); } // Build the geometry const line = new MeshLine(); line.setGeometry(points); const geometry = line.geometry; // Build the material with good parameters to animate it. const material = new MeshLineMaterial({ transparent: true, lineWidth: 0.1, color: new Color('#ff0000'), dashArray: 2, // always has to be the double of the line dashOffset: 0, // start the dash at zero dashRatio: 0.75, // visible length range min: 0.99, max: 0.5 }); // Build the Mesh const lineMesh = new Mesh(geometry, material); lineMesh.position.x = -4.5; // ! Assuming you have your own webgl engine to add meshes on scene and update them. webgl.add(lineMesh); // ! Call each frame function update() { // Check if the dash is out to stop animate it. if (lineMesh.material.uniforms.dashOffset.value < -2) return; // Decrement the dashOffset value to animate the path with the dash. lineMesh.material.uniforms.dashOffset.value -= 0.01; }

Create your own line style

Now that you know how to animate lines, I will show you some tips on how to customize the shape of your lines.

Use SplineCurve or CatmullRomCurve3

These classes smooth an array of points that is roughly positioned. They are perfect to build curved and fluid lines and keep control of them (length, orientation, turbulences…).

For instance, let’s add some turbulences to our previous array of points:

const segmentLength = 1; const nbrOfPoints = 10; const points = []; const turbulence = 0.5; for (let i = 0; i < nbrOfPoints; i++) { // ! We have to wrapped points into a THREE.Vector3 this time points.push(new Vector3( i * segmentLength, (Math.random() * (turbulence * 2)) - turbulence, (Math.random() * (turbulence * 2)) - turbulence, )); }

Then, use one of these classes to smooth your array of lines before you create the geometry:

// 2D spline // const linePoints = new Geometry().setFromPoints(new SplineCurve(points).getPoints(50)); // 3D spline const linePoints = new Geometry().setFromPoints(new CatmullRomCurve3(points).getPoints(50)); const line = new MeshLine(); line.setGeometry(linePoints); const geometry = line.geometry;

And like that you create your smooth curved line!

Note that SplineCurve only smoothes in 2D (x and y axis) compared to CatmullRomCurve3 that takes into account three axes.

I recommend to use the SplineCurve, anyway. It is more performant to calculate lines and is often enough to create the desired curved effect.

For instance, my demos Confetti and Energy are only made with the SplineCurve method:

Use Raycasting

Another technique taken from a THREE.MeshLine example is using a Raycaster to scan a Mesh already present in the scene.

Thus, you can create your lines that follow the shape of an object:

const radius = 4; const yMax = -4; const points = []; const origin = new Vector3(); const direction = new Vector3(); const raycaster = new Raycaster(); let y = 0; let angle = 0; // Start the scan while (y < yMax) { // Update the orientation and the position of the raycaster y -= 0.1; angle += 0.2; origin.set(radius * Math.cos(angle), y, radius * Math.sin(angle)); direction.set(-origin.x, 0, -origin.z); direction.normalize(); raycaster.set(origin, direction); // Save the coordinates raycsted. // !Assuming the raycaster cross the object in the scene each time const intersect = raycaster.intersectObject(objectToRaycast, true); if (intersect.length) { points.push( intersect[0].point.x, intersect[0].point.y, intersect[0].point.z, ); } }

This method is employed in the Boreal Sky demo. Here I used a sphere part as geometry to create the mesh objectToRaycast :

Now, you have enough tools to play and animate MeshLines. Many of these methods are inspired by the library’s examples. Feel free to explore these and share your own experiments and methods to create your own lines!

References and Credits