almcd almcd - 23 days ago 6
Javascript Question

Animate the drawing of a line in Three.js

I want to animate the drawing of a line on screen using Three.js. In this case the line I’m looking to draw is a Lorenz attractor, using this YouTube tutorial as a guide.

There’s a snippet of what I’ve created so far available at:



// CONFIGURE SCENE
// ------------------------------------

// Create Scene - acts as container
var scene = new THREE.Scene();

// Create camera - (field of view, aspect ratio, near and far planes)
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

// Renderer - webgl
var renderer = new THREE.WebGLRenderer( { alpha: true, antialias: true } );
renderer.setClearColor( 0x000000, 0 ); // set to show background of page

// Tell renderer to render to size of window
renderer.setSize( window.innerWidth, window.innerHeight );

// Add renderer to DOM
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);

// ADD GEOMETRY
// ------------------------------------
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;
var points = [];

// A mesh is made up of geometry and material
// Geometry is like a scaffold. Made up of x,y,z coordinates called vertices
// Material is the fill (faces) of the geometry

// Create Material (MeshBasic is not influenced by light)
var material = new THREE.LineBasicMaterial({
color: 0x0000ff
});

var geometry = new THREE.Geometry();

// Create mesh, passing in geometry and material
var line = new THREE.Line(geometry, material);

// Calculate the 50000 Lorenz attractor vertices
for (var i = 0; i < 50000; i++) {
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;

geometry.vertices.push(new THREE.Vector3(x, y, z));
}

// Add line to scene
scene.add(line);

// Move the camera out, else our camera will be at 0,0,0 and the attractor won't be visible by default
camera.position.z = 80;

// RENDER LOOP
// ------------------------------------
function render() {

/**
// Does not work - experimenting with animating the drawing of the attractor
// ------------------------------------
// Calculate the Lorenz attractor vertices
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;

var vect = new THREE.Vector3(x, y, z); // Create three.js vector
geometry.vertices.push(vect); // Add vertice to geometry
// ------------------------------------
**/

renderer.render(scene, camera); // Render scene and camera

// Rotate the attractor
line.rotation.x += 0.001;
line.rotation.y += 0.001;

requestAnimationFrame(render); // Call animation loop recursively
}
render(); // Initial call to loop

body {
margin: 0;
overflow: hidden;
background-color: #ccc;
}
canvas {
width: 100%;
height: 100%;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.js"></script>
<script src="https://s3-eu-west-1.amazonaws.com/code-pen/OrbitControls.js"></script>





As you can see, I'm able to successfully draw the Lorenz attractor, before adding it the scene.

However, I can't animate the drawing of the attractor, by pushing new vertices onto the geometry within the render loop. Doing so causes the line not to be visible on screen. You can see where I've experimented with this approach in the commented out section of JavaScript from line 73 onwards.

Some searching has brought up the idea of using Three.js’s BufferGeometry class. However, I’m unclear as to what exactly that class does or how to apply it in this instance.

Any guidance would be appreciated.

Answer

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