MeshLine

repository·master·Indexed 18 days ago

https://github.com/pmndrs/meshline

A high-performance replacement for THREE.Line in Three.js that uses a strip of billboarded triangles to support variable widths, textures, and advanced visual effects like dashing. It provides MeshLineGeometry for defining paths with optional width callbacks, MeshLineMaterial for shader-based styling (including gradients and size attenuation), and specialized raycasting utilities for interaction detection.

Tokens
4.1K
Snippets
12
Records
19
Agent score
62%

What's inside meshline

  1. How to use MeshLine with Three.js

    master

    To create a line, you must combine MeshLineGeometry and MeshLineMaterial into a standard THREE.Mesh. To enable interaction (like clicking or hovering), you must manually assign the raycast function from meshline to your mesh instance.

    import * as THREE from 'three'
    import { MeshLineGeometry, MeshLineMaterial, raycast } from 'meshline'
    
    const geometry = new MeshLineGeometry()
    geometry.setPoints([...])
    
    const material = new MeshLineMaterial({ ... })
    
    const mesh = new THREE.Mesh(geometry, material)
    mesh.raycast = raycast
    
    scene.add(mesh)
  2. Add TypeScript types for react-three-fiber

    master

    If using TypeScript with @react-three/fiber, add these declarations to your entry point to enable autocompletion and type checking for meshLineGeometry and meshLineMaterial elements.

    import { Object3DNode, MaterialNode } from '@react-three/fiber'
    import { MeshLineGeometry, MeshLineMaterial } from 'meshline'
    
    declare module '@react-three/fiber' {
      interface ThreeElements {
        meshLineGeometry: Object3DNode<MeshLineGeometry, typeof MeshLineGeometry>
        meshLineMaterial: MaterialNode<MeshLineMaterial, typeof MeshLineMaterial>
      }
    }
  3. Use MeshLine declaratively in react-three-fiber

    master

    To use MeshLine in @react-three/fiber, you must first extend the components. MeshLineGeometry provides a points prop and a widthCallback prop for variable widths.

    import { Canvas, extend } from '@react-three/fiber'
    import { MeshLineGeometry, MeshLineMaterial, raycast } from 'meshline'
    
    // Register components with R3F
    extend({ MeshLineGeometry, MeshLineMaterial })
    
    function App() {
      const points = [0, 0, 0, 1, 0, 0]
      
      return (
        <Canvas>
          <mesh raycast={raycast} onPointerOver={() => console.log('Hovered!')}>
            <meshLineGeometry 
              points={points} 
              widthCallback={(p) => p * Math.random()} 
            />
            <meshLineMaterial lineWidth={1} color="hotpink" />
          </mesh>
        </Canvas>
      )
    }
  4. Enable Raycasting for MeshLine

    master

    By default, THREE.Mesh does not know how to raycast against the custom geometry of a MeshLine. To enable mouse interactions (like onPointerOver), you must overwrite the mesh's raycast method with the raycast function provided by meshline.

    import { raycast } from 'meshline'
    
    // ... after creating mesh
    mesh.raycast = raycast
  5. Assign points to MeshLineGeometry

    master

    Use the .setPoints() method on a MeshLineGeometry instance to define the line's path.

    Supported inputs:

    • Float32Array
    • THREE.BufferGeometry
    • Array<THREE.Vector3 | THREE.Vector2 | [number, number, number] | [number, number] | number>

    Variable Widths: You can pass a second argument to .setPoints(), which is a callback function (p) => number. The parameter p is a decimal percentage (0 to 1) representing the point's position along the line. This allows you to create tapered, sinusoidal, or otherwise varying line widths.

    const geometry = new MeshLineGeometry()
    const points = [
      Math.cos(0), Math.sin(0), 0,
      // ... more points
    ]
    
    // Basic usage
    geometry.setPoints(points)
    
    // Variable width usage (e.g., tapering)
    geometry.setPoints(points, (p) => 1 - p)
    
    // Sinusoidal width
    geometry.setPoints(points, (p) => 2 + Math.sin(50 * p))
  6. Configure MeshLineMaterial options

    master

    The MeshLineMaterial controls the visual appearance of the line.

    Important Note: If you are rendering transparent lines or using a texture with an alpha map, you should set depthTest to false, transparent to true, and choose an appropriate blending mode (or use alphaTest).

    Required Property:

    • resolution: THREE.Vector2 specifying the canvas size. This is REQUIRED for correct rendering.
    const material = new MeshLineMaterial({
      resolution: new THREE.Vector2(window.innerWidth, window.innerHeight),
      lineWidth: 1,
      color: new THREE.Color('hotpink'),
      // ... other options
    })
  7. MeshLineMaterial property reference

    master

    The following properties are available on MeshLineMaterial:

    PropertyTypeDescription
    mapTHREE.TextureTexture to paint along the line (requires useMap: true)
    useMapnumber (0 or 1)Enables/disables texture mapping
    alphaMapTHREE.TextureTexture for alpha (requires useAlphaMap: true)
    useAlphaMapnumber (0 or 1)Enables/disables alpha mapping
    repeatTHREE.Vector2Texture tiling (applies to map and alphaMap)
    colorTHREE.ColorColor of the line width or tint for the texture
    opacitynumber (0-1)Alpha value (requires transparent: true)
    alphaTestnumber (0-1)Cutoff value for alpha testing
    dashArraynumberLength and space between dashes (0 for no dash)
    dashOffsetnumberStarting location of the dash (useful for animation)
    dashRationumberRatio of visibility (0 is more visible, 1 is more invisible)
    resolutionTHREE.Vector2REQUIRED: The canvas size
    sizeAttenuationnumber (0 or 1)1: constant width (world units); 0: attenuates with distance (screen pixels)
    lineWidthnumberWidth value (units depend on sizeAttenuation)
  8. Enable raycasting for MeshLine meshes

    master

    To enable intersection testing with a MeshLine mesh, you must assign the raycast function to the mesh's onBeforeRender or more commonly, provide it as a custom raycasting method. In Three.js, you can achieve this by overriding the raycast method on your Mesh instance.

    This function allows the THREE.Raycaster to detect intersections with the line's geometry, accounting for the line's width and the threshold parameter defined in the raycaster's params. It calculates intersections based on the distance from the ray to the line segments, considering the lineWidth from the material and the width attribute from the geometry.

    import * as THREE from 'three';
    import { raycast } from 'meshline/src/raycast';
    
    // Assuming 'mesh' is a THREE.Mesh with MeshLine geometry and MeshLineMaterial
    // @ts-ignore
    mesh.raycast = raycast;
    
    // Now standard Three.js raycasting will work:
    const intersects = raycaster.intersectObject(mesh);
  9. MeshLineMaterial Properties

    master

    MeshLineMaterial exposes its shader uniforms as direct properties on the class instance. You can update these properties at runtime to change the appearance of the line.

    Available Properties

    • lineWidth: number
    • map: THREE.Texture
    • useMap: number
    • alphaMap: THREE.Texture
    • useAlphaMap: number
    • color: THREE.Color
    • gradient: THREE.Color[]
    • opacity: number
    • resolution: THREE.Vector2 (Updating this uses .copy() internally)
    • sizeAttenuation: number
    • dashArray: number (Setting this non-zero automatically sets useDash to 1)
    • dashOffset: number
    • dashRatio: number
    • useDash: number
    • useGradient: number
    • visibility: number
    • alphaTest: number
    • repeat: THREE.Vector2 (Updating this uses .copy() internally)
  10. Animate lines using advance()

    master

    The advance({ x, y, z }: THREE.Vector3) method provides a high-performance way to animate a line by shifting its positions. It works by moving the existing positions forward and adding a new point at the end, effectively creating a 'trailing' effect.

    This method is optimized using memcpy to shift the internal position, previous, and next buffers efficiently.

    Note: This assumes the geometry was initialized with a fixed number of points that you intend to cycle through.

    // Inside an animation loop
    const newPoint = new THREE.Vector3(Math.sin(time), Math.cos(time), 0)
    meshLineGeometry.advance(newPoint)
  11. Update MeshLineGeometry points via setPoints()

    master

    Use setPoints(points, wcb?) to update the geometry's vertices and width profile. This method automatically recalculates the internal attributes (position, previous, next, side, width, uv, index, and counters) and updates the bounding box/sphere.

    • points: One of the supported PointsRepresentation types.
    • wcb: An optional WidthCallback function (p: number) => any.

    Note: Setting the points property directly on the instance also triggers setPoints.

    // Using the setter
    geometry.points = myPointsArray
    
    // Or using the explicit method
    geometry.setPoints(myPointsArray, (p) => Math.sin(p) * 2)