4

I've got a THREE.LineSegments object, and I want to change the number of vertices dynamically. When I modify the geometry vertices array, though, any lines with vertices that were removed just stay put.

Is there a way to remove vertices after the geometry has been created?

e.g., Below I'm taking a LineSegments object with 3 segments, and trying to change it later to have only 2 segments. The last line segment remains.

var scene,
    renderer,
    camera;

var line;

initScene();
initLine();

setInterval(update, 500);


function initScene() {

  camera   = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000),
  scene    = new THREE.Scene();
  renderer = new THREE.WebGLRenderer();

  camera.position.z = 5;
  scene.add(camera);

  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

}

function initLine() {

  var verts = [
    randomV3(),
    randomV3(),
    randomV3(),
    randomV3()
  ];

  var geom = new THREE.Geometry();

  geom.vertices = [
    verts[0], verts[1],
    verts[1], verts[2],
    verts[2], verts[3]
  ];

  line = new THREE.LineSegments(geom, new THREE.LineBasicMaterial({
    color: 0xff00ff,
    linewidth: 3
  }));

  scene.add(line);
  renderer.render(scene, camera);

}

function update() {

  var verts = [
    randomV3(),
    randomV3(),
    randomV3()
  ];

  line.geometry.vertices = [
    verts[0], verts[1],
    verts[1], verts[2]
  ];
  line.geometry.verticesNeedUpdate = true;

  renderer.render(scene, camera);

}

function randomV3() {
  return new THREE.Vector3(
    (Math.random() * 4) - 2,
    (Math.random() * 4) - 2,
    0
  )
}
body {
  margin: 0;
  padding: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/103/three.min.js"></script>
Scott Thiessen
  • 873
  • 7
  • 20

1 Answers1

4

One approach to solve this problem is to dispose the old geometry and then create a new one like so:

line.geometry.dispose();

line.geometry = new THREE.Geometry();

line.geometry.vertices = [
  verts[0], verts[1],
  verts[1], verts[2]
];

This approach is demonstrated in the following fiddle. However, consider to use THREE.BufferGeometry in order to have a more future-proof solution (THREE.Geometry will not be renderable at some point anymore). Here is a fiddle with the same code but with THREE.BufferGeometry.

Instead of disposing the geometry, you could also create a THREE.BufferGeometry with enough buffer space so it can represent the biggest line object in your application. This approach is necessary since you can't resize buffers, only update their contents. The details are explained in this guide:

https://threejs.org/docs/index.html#manual/en/introduction/How-to-update-things

BTW: Setting linewidth has no effect when rendering line primitives in three.js. The always have the width of 1 pixel.

three.js R103

Mugen87
  • 28,829
  • 4
  • 27
  • 50
  • Thanks! I thought about disposing & recreating the geometry, but seemed a little clumsy. I like the `THREE.BufferGeometry` route, but using the `setDragRange` solution @WestLangley linked too. – Scott Thiessen Apr 02 '19 at 22:30
  • I think your `linewidth` note may actually be a browser issue (https://github.com/mrdoob/three.js/issues/10357). It works as expected for me in macOS Safari, but not Chrome. – Scott Thiessen Apr 02 '19 at 22:32
  • 1
    It's actually not recommended to set this parameter (see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/lineWidth). This will not be fixed in Chrome or Firefox since "wide" lines are not a native primitive of any modern hardware. They require emulation in either the driver or the application. Because of this, you should render wide lines always as polygons. – Mugen87 Apr 03 '19 at 08:46
  • You saved me! Thanks :-) – Necromancer Dec 09 '21 at 06:58