Drawing a Line with Three.Js Dynamically

Drawing a line with three.js dynamically

You can animate a line -- or increase the number of points rendered -- very easily using BufferGeometry and the setDrawRange() method. You do need to set a maximum number of points, however.

const MAX_POINTS = 500;

// geometry
const geometry = new THREE.BufferGeometry();

// attributes
const positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );

// drawcalls
drawCount = 2; // draw the first 2 points, only
geometry.setDrawRange( 0, drawCount );

// material
const material = new THREE.LineBasicMaterial( { color: 0xff0000 } );

// line
line = new THREE.Line( geometry, material );
scene.add( line );

If you want to change the number of points rendered after the first render, do this:

line.geometry.setDrawRange( 0, newValue );

If you want to change the position data values after the first render, you set the needsUpdate flag like so:

line.geometry.attributes.position.needsUpdate = true; // required after the first render

Here is a fiddle showing an animated line which you can adapt to your use case.

three.js r.147

how to draw a dynamic line in threejs with mouse down between two points using buffergeometry

Try MeshLine, Mesh replacement for THREE.Line

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

Dynamically Adding Vertices to a Line in Three.js

EDIT: Using BufferGeometry and drawcalls you can now implement equivalent functionality. See Drawing a line with three.js dynamically.

three.js r.71


Dynamically adding vertices to a line is not supported. As stated in the Wiki:

You can only update content of buffers, you cannot resize buffers (this is very costly, basically equivalent to creating new geometry).

You can emulate resizing by pre-allocating a larger buffer and then keeping unneeded vertices collapsed / hidden.

three.js r.55

Animate the drawing of a line in Three.js

Looking at this SO answer, you can combine this answer with your jsbin code. All that you have to do is to put your global variabels with attractor initials

var MAX_POINTS = 50000;

var x = -12.1;
var y = -22;
var z = 0;

var a = 10; // sigma
var b = 28; // beta
var c = 8/3; // rho

var dt, dx, dy, dz;

and make a small change to the updatePositions() function, how you will set coordinates for an adding line segment

var index = 0;
...
dt = 0.01;
dx = (a * (y - x)) * dt;
dy = (x * (b - z) - y) * dt;
dz = (x * y - c * z) * dt;

x = x + dx;
y = y + dy;
z = z + dz;

jsfiddle example

Drawing a line between moving objects

In your animation loop you have to set line.geometry.verticesNeedUpdate = true. Because every time after rendering it becomes false. jsfiddle example

Dynamically adding faces to a three.js geometry

You want to add faces to an existing geometry.

Since buffers can't be resized, the best solution is to switch to BufferGeometry, preallocate sufficiently-sized buffers, and set the drawRange. See this SO answer. This answer, too.

If you add vertices, you will need to recompute the bounding sphere for frustum culling to work correctly.

geometry.computeBoundingSphere();

Or, as you said, you can disable frustum culling:

mesh.frustumCulled = false;

three.js.r.91

How to smoothly animate drawing of a line

You can smoothly animate the drawing of a line -- even if the line consists of only a few points -- by using LineDashedMaterial.

The trick is to render only one dash, and increment the length of the dash in the animation loop.

// geometry
var geometry = new THREE.BufferGeometry();

// attributes
numPoints = points.length; // points is an array of Vector3
var positions = new Float32Array( numPoints * 3 ); // 3 vertices per point
var colors = new Float32Array( numPoints * 3 ); // 3 channels per point
var lineDistances = new Float32Array( numPoints * 1 ); // 1 value per point

geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
geometry.setAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
geometry.setAttribute( 'lineDistance', new THREE.BufferAttribute( lineDistances, 1 ) );

// populate
var color = new THREE.Color();

for ( var i = 0, index = 0, l = numPoints; i < l; i ++, index += 3 ) {

positions[ index ] = points[ i ].x;
positions[ index + 1 ] = points[ i ].y;
positions[ index + 2 ] = points[ i ].z;

color.setHSL( i / l, 1.0, 0.5 );

colors[ index ] = color.r;
colors[ index + 1 ] = color.g;
colors[ index + 2 ] = color.b;

if ( i > 0 ) {

lineDistances[ i ] = lineDistances[ i - 1 ] + points[ i - 1 ].distanceTo( points[ i ] );

}

}

lineLength = lineDistances[ numPoints - 1 ];

// material
var material = new THREE.LineDashedMaterial( {

vertexColors: true,
dashSize: 1, // to be updated in the render loop
gapSize: 1e10 // a big number, so only one dash is rendered

} );

// line
line = new THREE.Line( geometry, material );
scene.add( line );

Then, in the animation loop:

fraction = ( fraction + 0.001 ) % 1; // fraction in [ 0, 1 ]

line.material.dashSize = fraction * lineLength;

Note: You can compute the line distances any way you want. For example, you could normalize the distances by the total length, so the distance to the last point is 1. You would then vary dashSize from 0 to 1.


Compare this approach with this alternate method.

three.js r.143



Related Topics



Leave a reply



Submit