Three.js - Drawing Lines
Three.js - Drawing Lines
Section titled “Three.js - Drawing Lines”After exploring various materials in Three.js, let’s dive into materials specifically designed for drawing lines. Lines are fundamental for creating wireframes, outlines, paths, and various geometric patterns in your 3D scenes.
Fundamentals of Line Creation
Section titled “Fundamentals of Line Creation”The core of drawing a line in Three.js involves two main components: a geometry defining the path of the line, and a material defining its appearance.
Defining the Path with BufferGeometry
Section titled “Defining the Path with BufferGeometry”THREE.BufferGeometry is the modern, high-performance way to define any custom shape in Three.js. To create a line, you provide it with a series of points, or vertices, that the line will connect in sequence.
import * as THREE from 'three';
// 1. Define the points (vertices) of the lineconst points = [];points.push(new THREE.Vector3(-10, 0, 0)); // Start pointpoints.push(new THREE.Vector3(0, 10, 0)); // Middle pointpoints.push(new THREE.Vector3(10, 0, 0)); // End point
// 2. Create a BufferGeometry from the pointsconst geometry = new THREE.BufferGeometry().setFromPoints(points);Here, THREE.Vector3(x, y, z) creates a point in 3D space. We create an array of these vectors and then use the .setFromPoints() method to efficiently construct our geometry.
Note: THREE.Line draws segments between each consecutive pair of vertices. It does not automatically connect the last vertex to the first to close the loop. For a closed line, you must add the first point again at the end of the array.
Choosing a Line Material
Section titled “Choosing a Line Material”Three.js offers two primary materials for lines:
// For a solid, continuous lineconst material = new THREE.LineBasicMaterial({ color: 0x00ff00 });
// For a dashed lineconst dashedMaterial = new THREE.LineDashedMaterial({ color: 0xffea00, linewidth: 1, // Note: this is largely ignored, see below scale: 1, dashSize: 3, // Length of a dash gapSize: 1, // Length of the gap between dashes});Once you have your geometry and material, you combine them using THREE.Line:
const line = new THREE.Line(geometry, material);scene.add(line);
// For dashed lines, you MUST compute line distancesconst dashedLine = new THREE.Line(geometry, dashedMaterial);dashedLine.computeLineDistances();scene.add(dashedLine);Common Pitfall: Line Width
Section titled “Common Pitfall: Line Width”A frequent point of confusion is the linewidth property on LineBasicMaterial and LineDashedMaterial. Due to limitations in how modern GPUs render lines (specifically in the underlying WebGL API), setting linewidth to a value greater than 1 will not have an effect on most platforms.
If you need to render lines with a controllable, thick width, you must use more advanced techniques. A popular solution is to use Line2 from the Three.js examples, which builds the line from a thin mesh. This approach offers more visual control at the cost of slightly more complex setup and performance.
Interactive Example: Dynamic Line Drawing
Section titled “Interactive Example: Dynamic Line Drawing”The following example demonstrates creating a basic line and uses the modern lil-gui library to allow real-time manipulation of its vertices. This showcases a more efficient way to update geometries compared to recreating them on every change.
Setup and Code
Section titled “Setup and Code”This example assumes a modern JavaScript development environment. You can set up a project quickly using a tool like Vite.
- Initialize your project:
npm create vite@latest my-threejs-app -- --template vanilla - Install dependencies:
cd my-threejs-appand thennpm install three lil-gui
main.js
Section titled “main.js”import * as THREE from 'three';import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';import GUI from 'lil-gui';
/** * Base Setup */// GUIconst gui = new GUI();
// Sceneconst scene = new THREE.Scene();scene.background = new THREE.Color(0x1a1a1a);
// Cameraconst sizes = { width: window.innerWidth, height: window.innerHeight};const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100);camera.position.set(0, 5, 20);scene.add(camera);
// Rendererconst renderer = new THREE.WebGLRenderer({ antialias: true});renderer.setSize(sizes.width, sizes.height);renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));document.body.appendChild(renderer.domElement);
// Controlsconst controls = new OrbitControls(camera, renderer.domElement);controls.enableDamping = true;
/** * Line Drawing */// 1. Define Pointsconst points = [];points.push(new THREE.Vector3(-10, 0, 0));points.push(new THREE.Vector3(0, 10, -5));points.push(new THREE.Vector3(10, 0, 0));
// 2. Create Geometryconst geometry = new THREE.BufferGeometry().setFromPoints(points);
// 3. Create Materialconst material = new THREE.LineBasicMaterial({ color: 0x00ff00 });
// 4. Create Lineconst line = new THREE.Line(geometry, material);scene.add(line);
/** * GUI for real-time updates */function updateLine() { // More performant: update the existing geometry's positions line.geometry.setFromPoints(points);}
points.forEach((point, i) => { const folder = gui.addFolder(`Point ${i + 1}`); folder.add(point, 'x', -15, 15, 0.1).name('X').onChange(updateLine); folder.add(point, 'y', -15, 15, 0.1).name('Y').onChange(updateLine); folder.add(point, 'z', -15, 15, 0.1).name('Z').onChange(updateLine); folder.open();});
/** * Responsiveness */window.addEventListener('resize', () => { sizes.width = window.innerWidth; sizes.height = window.innerHeight;
camera.aspect = sizes.width / sizes.height; camera.updateProjectionMatrix();
renderer.setSize(sizes.width, sizes.height); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));});
/** * Animation Loop */const tick = () => { controls.update(); renderer.render(scene, camera); window.requestAnimationFrame(tick);};
tick();Dashed Lines Example
Section titled “Dashed Lines Example”To create a dashed line, simply swap the material and remember to call .computeLineDistances() on the Line object. This extra step is necessary for Three.js to calculate how to apply the dashes and gaps correctly along the line’s length.
// ... (setup is the same as above)
// Create a Dashed Materialconst dashedMaterial = new THREE.LineDashedMaterial({ color: 0xffea00, dashSize: 1, gapSize: 0.5});
// Create the Line objectconst dashedLine = new THREE.Line(geometry, dashedMaterial);
// CRITICAL STEP for dashed linesdashedLine.computeLineDistances();
scene.add(dashedLine);Practical Applications & Next Steps
Section titled “Practical Applications & Next Steps”Drawing lines is a versatile skill. You can use it to:
- Visualize data: Create line graphs in 3D space.
- Outline objects: Draw a wireframe of a complex model for artistic or debugging purposes.
- Create helpers: Draw grids, axes, or other guides in your scene.
- Illustrate paths: Show the trajectory of an object in an animation.
Experiment by adding more points, creating closed loops, or even animating the points’ positions over time within the tick function for dynamic effects.