How to draw multiple line strips in one draw call?

I have a number of line strips (THREE.Line) that I need to draw and I was hoping I could group them all together into a single draw call. Is there a way to do this? With triangle strips, I can add degenerate triangles between each strip and have them all drawn together in one draw call. Is there a trick to do the same thing with line strips?

I see that in the OpenGL spec I could put all the line strips together and separate them with a reset index specified by glPrimitiveRestartIndex (glPrimitiveRestartIndex - OpenGL 4 Reference Pages)

Is there a way to do the same sort of thing with THREE.js ?

Hi!
What about using THREE.LineSegments() with an indexed buffer geometry?
https://threejs.org/examples/?q=index#webgl_buffergeometry_lines_indexed

Yes I could convert my line strips into lines, I was just hoping I could do something else that didn’t require me to enlarge my index buffer so drastically.

Just found this https://www.khronos.org/registry/webgl/specs/latest/2.0/#NO_PRIMITIVE_RESTART_FIXED_INDEX

I’m going to try it out to see if if works

This will only work with WebGL 2.

does THREE.JS use webgl 2 or 1?

The latest release (R95) added support for working with a WebGL 2 context. But the device/browser support might be still problematic for projects.

You can use the following example code if you want to experiment with three.js and WebGL 2.

So what’s the verdict? Can anyone provide sample code that implements line strips with occasional discontinuities?

The verdict seems to be (like said prisoner849):

  • Use LineSegments

  • Give your indexes to the Geometry:
    ,

let’s say you have 2 curves. Each curve has 4 points. The indexes would be:
[0,1, 1,2 , 2,3, 4,5, 5,6, 7,8]
[0,1, 1,2 , 2,3, < 1st line - 2nd line > 4,5, 5,6, 7,8]

Here is a working example using drei library and created thanks to @prisoner849 :slight_smile: codesandbox

Just tried this on WebGL2 with the primitive-restart method. Works like a charm.

After asserting that renderer.capabilities.isWebGL2 is true, the aforementioned example with 2 curves made up of 4 points each can be drawn as Line with an index array of e.g.
Uint16Array.from([0, 1, 2, 3, 0xffff, 4, 5, 6, 7])

For reproduction: Primitive Restart Index with Line Strip - JSFiddle - Code Playground

Since r163 you can safely do this for all instances of THREE.Line since WebGL 1 is no longer supported by WebGLRenderer. And since PRIMITIVE_RESTART_FIXED_INDEX is always enabled with WebGL 2 (see WebGL 2.0 Specification), there is no further configuration required.

Full code:

import * as THREE from 'three';

let renderer, scene, camera;

init();
render();

function init() {

    scene = new THREE.Scene();
    
    camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.position.set( 0, 0, 4 );
    
    const geometry = new THREE.BufferGeometry();
    const positionAttribute = new THREE.Float32BufferAttribute( [
      - 1,   1, 0,
      - 1, - 1, 0, 
        0,   1, 0,
        0, - 1, 0,
        1,   1, 0,
        1, - 1, 0
    ], 3 );

    // 65535 is the restart index for Uint16
    const index = new THREE.Uint16BufferAttribute( [ 0, 1, 2, 65535, 3, 4, 5 ], 1 ); 
    
    geometry.setAttribute( 'position', positionAttribute );
    geometry.setIndex( index );
    
    const material = new THREE.LineBasicMaterial( { color: 0xffffff } );
    
    const mesh = new THREE.Line( geometry, material );
    scene.add( mesh );

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.setPixelRatio( window.devicePixelRatio );
    document.body.appendChild( renderer.domElement );

}

function render() {

    renderer.render( scene, camera );

}