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.

1 Like

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

1 Like

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

1 Like

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])

1 Like

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 );

}