spite / THREE.MeshLine

Mesh replacement for THREE.Line
MIT License
2.17k stars 380 forks source link
glsl line shader threejs webgl

MeshLine

Mesh replacement for THREE.Line

Instead of using GL_LINE, it uses a strip of triangles billboarded. Some examples:

Demo Graph Spinner SVG Shape Shape

How to use

Include the script

Include script after THREE is included

<script src="https://github.com/spite/THREE.MeshLine/raw/master/THREE.MeshLine.js"></script>

or use npm to install it

npm i three.meshline

and include it in your code (don't forget to require three.js)

const THREE = require('three');
const MeshLine = require('three.meshline').MeshLine;
const MeshLineMaterial = require('three.meshline').MeshLineMaterial;
const MeshLineRaycast = require('three.meshline').MeshLineRaycast;

or

import * as THREE from 'three';
import { MeshLine, MeshLineMaterial, MeshLineRaycast } from 'three.meshline';
Create an array of 3D coordinates

First, create the list of numbers that will define the 3D points for the line.

const points = [];
for (let j = 0; j < Math.PI; j += (2 * Math.PI) / 100) {
  points.push(Math.cos(j), Math.sin(j), 0);
}

MeshLine also accepts a BufferGeometry looking up the vertices in it.

const points = [];
for (let j = 0; j < Math.PI; j += 2 * Math.PI / 100) {
  points.push(new THREE.Vector3(Math.cos(j), Math.sin(j), 0));
}
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const line = new MeshLine();
line.setGeometry(geometry);
Create a MeshLine and assign the points

Once you have that, you can create a new MeshLine, and call .setPoints() passing the list of points.

const line = new MeshLine();
line.setPoints(points);

Note: .setPoints accepts a second parameter, which is a function to define the width in each point along the line. By default that value is 1, making the line width 1 * lineWidth in the material.

// p is a decimal percentage of the number of points
// ie. point 200 of 250 points, p = 0.8
line.setPoints(geometry, p => 2); // makes width 2 * lineWidth
line.setPoints(geometry, p => 1 - p); // makes width taper
line.setPoints(geometry, p => 2 + Math.sin(50 * p)); // makes width sinusoidal
Create a MeshLineMaterial

A MeshLine needs a MeshLineMaterial:

const material = new MeshLineMaterial(OPTIONS);

By default it's a white material of width 1 unit.

MeshLineMaterial has several attributes to control the appereance of the MeshLine:

If you're rendering transparent lines or using a texture with alpha map, you should set depthTest to false, transparent to true and blending to an appropriate blending mode, or use alphaTest.

Use MeshLine and MeshLineMaterial to create a THREE.Mesh

Finally, we create a mesh and add it to the scene:

const mesh = new THREE.Mesh(line, material);
scene.add(mesh);

You can optionally add raycast support with the following.

mesh.raycast = MeshLineRaycast;

Declarative use

THREE.meshline can be used declaritively. This is how it would look like in react-three-fiber. You can try it live here.

import { extend, Canvas } from 'react-three-fiber'
import { MeshLine, MeshLineMaterial, MeshLineRaycast } from 'three.meshline'

extend({ MeshLine, MeshLineMaterial })

function Line({ points, width, color }) {
  return (
    <Canvas>
      <mesh raycast={MeshLineRaycast}>
        <meshLine attach="geometry" points={points} />
        <meshLineMaterial
          attach="material"
          transparent
          depthTest={false}
          lineWidth={width}
          color={color}
          dashArray={0.05}
          dashRatio={0.95}
        />
      </mesh>
    </Canvas>
  )
}

Dynamic line widths can be set along each point using the widthCallback prop.

<meshLine attach='geometry' points={points} widthCallback={pointWidth => pointWidth * Math.random()} />

TODO

Support

Tested successfully on

References

License

MIT licensed

Copyright (C) 2015-2016 Jaume Sanchez Elias, http://www.clicktorelease.com