Three.js - Drawing Lines



You have learned about quite a lot of materials in Three.js. Now let's see some unique materials used in drawing lines. We can draw various shapes and patterns using lines.

Using BufferGeometry

THREE.BufferGeometry is the base class of all the built-in geometries in Three.js. You can create your geometry by passing an array of vertices of the geometry.

Learn more about BufferGeometry here.

const points = []
points.push(new THREE.Vector3(-10, 0, 0))
points.push(new THREE.Vector3(0, -10, 0))
points.push(new THREE.Vector3(10, 0, 0))

These are some additional elements Three.js provides us to create our geometries. THREE.Vector3(x, y, z) - It makes a point in 3D space. In the above code, we are adding 3 points to the points array.

const geometry = new THREE.BufferGeometry().setFromPoints(points)

THREE.BufferGeometry(), as mentioned before it creates our geometry. We use the setFromPoints method to set the geometry using the array of points.

Note − Lines are drawn between each consecutive pair of vertices, but not between the first and last (the line is not closed.)

const material = new THREE.LineBasicMaterial({
   // for normal lines
   color: 0xffffff,
   linewidth: 1,
   linecap: 'round', //ignored by WebGLRenderer
   linejoin: 'round', //ignored by WebGLRenderer
})
// or
const material = new THREE.LineDashedMaterial({
   // for dashed lines
   color: 0xffffff,
   linewidth: 1,scale: 1,
   dashSize: 3,
   gapSize: 1,
})

These are the unique materials for lines. You can use any one of THREE.LineBasicMaterial or THREE.LineDashedMaterial.

const line = new THREE.Line(geometry, material)

Example

Now, instead of using THREE.Mesh, we use THREE.Line for drawing lines. Now, you see a "V" shape drawn using lines on the screen.

linebasic.html

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8" />
      <meta http-equiv="X-UA-Compatible" content="ie=edge" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Three.js - Line basic</title>
      <style>
         * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
               Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
         }
         html,
         body {
            height: 100vh;
            width: 100vw;
         }
         #threejs-container {
            position: block;
            width: 100%;
            height: 100%;
         }
      </style>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script>
   </head>
   <body>
      <div id="threejs-container"></div>
      <script type="module">
         // Creating a line using LineBasicMaterial

         // GUI
         const gui = new dat.GUI()
         // sizes
         let width = window.innerWidth
         let height = window.innerHeight
         // scene
         const scene = new THREE.Scene()
         scene.background = new THREE.Color(0x262626)
         // camera
         const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100)
         camera.position.set(0, 0, 50)
         camera.lookAt(0, 0, 0)
         const camFolder = gui.addFolder('Camera')
         camFolder.add(camera.position, 'z', 10, 100)
         camFolder.open()
         // Line
         const points = []
         points.push(new THREE.Vector3(-10, 0, 0))
         points.push(new THREE.Vector3(0, -20, 0))
         points.push(new THREE.Vector3(10, 0, 0))
         const folders = [gui.addFolder('Poin 1'), gui.addFolder('Poin 2'), gui.addFolder('Poin 3')]
         folders.forEach((folder, i) => {
            folder.add(points[i], 'x', -30, 30, 1).onChange(redraw)
            folder.add(points[i], 'y', -30, 30, 1).onChange(redraw)
            folder.add(points[i], 'z', -30, 30, 1).onChange(redraw)
            folder.open()
         })
         const geometry = new THREE.BufferGeometry().setFromPoints(points)
         const material = new THREE.LineBasicMaterial({
            color: 0xffffff,
            linewidth: 2
         })
         const line = new THREE.Line(geometry, material)
         line.position.set(0, 10, 0)
         scene.add(line)
         function redraw() {
            let newGeometry = new THREE.BufferGeometry().setFromPoints(points)
            line.geometry.dispose()
            line.geometry = newGeometry
         }
         // responsiveness
         window.addEventListener('resize', () => {
            width = window.innerWidth
            height = window.innerHeight
            camera.aspect = width / height
            camera.updateProjectionMatrix()
            renderer.setSize(window.innerWidth, window.innerHeight)
            renderer.render(scene, camera)
         })
         // renderer
         const renderer = new THREE.WebGL1Renderer()
         renderer.setSize(width, height)
         renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
         // animation
         function animate() {
            requestAnimationFrame(animate)
            renderer.render(scene, camera)
         }
         // rendering the scene
         const container = document.querySelector('#threejs-container')
         container.append(renderer.domElement)
         renderer.render(scene, camera)
         animate()
      </script>
   </body>
</html>

Output

Example

You can create any type of geometry wireframe using lines by specifying the vertices. Check out the following example where we are drawing dashed lines.

dashedline.html

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8" />
      <meta http-equiv="X-UA-Compatible" content="ie=edge" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Three.js - Dashed line</title>
      <style>
         * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: -applesystem, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu,
               Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
         }
         html,
         body {
            height: 100vh;
            width: 100vw;
         }
         #threejs-container {
            position: block;
            width: 100%;
            height: 100%;
         }
      </style>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.js"></script>
   </head>
   <body>
      <div id="threejs-container"></div>
      <script type="module">
         // Creating dashed line using LineDashedMaterial
         // GUI
         const gui = new dat.GUI()
         // sizes
         let width = window.innerWidth
         let height = window.innerHeight
         // scene
         const scene = new THREE.Scene()
         scene.background = new THREE.Color(0x262626)
         // camera
         const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100)
         camera.position.set(0, 0, 50)
         camera.lookAt(0, 0, 0)
         const camFolder = gui.addFolder('Camera')
         camFolder.add(camera.position, 'z', 10, 100)
         camFolder.open()
         // Line
         const points = []
         points.push(new THREE.Vector3(-10, 0, 0))
         points.push(new THREE.Vector3(0, -20, 0))
         points.push(new THREE.Vector3(10, 0, 0))
         const folders = [gui.addFolder('Poin 1'), gui.addFolder('Poin 2'), gui.addFolder('Poin 3')]
         folders.forEach((folder, i) => {
            folder.add(points[i], 'x', -30, 30, 1).onChange(redraw)
            folder.add(points[i], 'y', -30, 30, 1).onChange(redraw)
            folder.add(points[i], 'z', -30, 30, 1).onChange(redraw)
            folder.open()
         })
         const geometry = new THREE.BufferGeometry().setFromPoints(points)
            const material = new THREE.LineDashedMaterial({
            color: 0xffffff,
            linewidth: 2,
            scale: 1,
            dashSize: 3,
            gapSize: 2
         })
         const line = new THREE.Line(geometry, material)
         line.computeLineDistances()
         line.position.set(0, 10, 0)
         scene.add(line)
         console.log(line)
         function redraw() {
            let newGeometry = new THREE.BufferGeometry().setFromPoints(points)
            line.geometry.dispose()
            line.geometry = newGeometry
         }
         // responsiveness
         window.addEventListener('resize', () => {
            width = window.innerWidth
            height = window.innerHeight
            camera.aspect = width / height
            camera.updateProjectionMatrix()
            renderer.setSize(window.innerWidth, window.innerHeight)
            renderer.render(scene, camera)
         })
         // renderer
         const renderer = new THREE.WebGL1Renderer()
         renderer.setSize(width, height)
         renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
         // animation
         function animate() {
            requestAnimationFrame(animate)
            renderer.render(scene, camera)
         }
         // rendering the scene
         const container = document.querySelector('#threejs-container')
         container.append(renderer.domElement)
         renderer.render(scene, camera)
         animate()
      </script>
   </body>
</html>

Output

Advertisements