Easter egg. Follow() function — moving 3D objects with a curve.

Introduction

Alexander Buzin
WhitestormJS Framework
2 min readMay 2, 2016

--

Some days ago I needed to make my parrot fly on trajectory. First thing that I remembered was THREE.Curve that has getPoint(u) method, where “u” is a value between 0 and 1. It will return a THREE.Vector3 object that stores coordinates of point, which locates at “u” × 100 percentage of curve’s length.

Logic

If I can know a point owned by curve knowing just a percentage from curve’s start — I can make object move by this curve changing it’s position each frame. There is how WHS.loop will help us now. We can calculate the percentage of completion of the object’s movement. It will be:

clock.getElapsedTime() * 1000 / gEnd

Where clock.getElapsedTime() is a time since the loop was started (in seconds) and gEnd is the a duration of our movement (in milliseconds).

Implementing object rotation

Now we now that we can get any point of the curve having movement’s time that updates each frame. Our object that will move is a WHS.Shape object, so we can get it’s three.js analog (THREE.Mesh) simply by calling .getNative() method on it. THREE.Mesh has .lookAt() method that rotates object to look directly at the point passed to this method. Our point for that will be the next point of this curve. We can find it simply by adding 0.01 to “u” in getPoint() method:

curve.getPoint( u + 0.01 );

But if “u” will be 1, we’ll get 1.01 passed into getPoint method and returned vector will be “undefined” + you will see error message in the console, so we should calculate it’s remainder of the division by one.

curve.getPoint( (u + 0.01) % 1 ); // Next point(vector3) of the curve.

Parrot flies along the curve

API part

WHS.Shape, WHS.Camera & WHS.Light

Follow() function is implemented using flexible WHS.loop function for making smooth animations in more performant way.

Using it with a WHS.Morph object will look like:

var curve = new THREE.CurvePath();curve.add(
new THREE.CubicBezierCurve3(
new THREE.Vector3( -100, 100, 50 ),
new THREE.Vector3( -100, 160, 300 ),
new THREE.Vector3( 200, 180, 30 ),
new THREE.Vector3( 100, 140, 80 )
)
);
curve.add(
new THREE.CubicBezierCurve3(
new THREE.Vector3( 100, 140, 80 ),
new THREE.Vector3( 200, 80, 150 ),
new THREE.Vector3( -200, 60, -100 ),
new THREE.Vector3( 200, 100, 350 )
)
);
curve.add(
new THREE.CubicBezierCurve3(
new THREE.Vector3( 200, 100, 350 ),
new THREE.Vector3( 200, 80, 150 ),
new THREE.Vector3( -200, 60, -100 ),
new THREE.Vector3( -100, 100, 50 )
)
);
parrot.addTo( GAME, “wait” ).then(function (obj) {
obj.follow(
curve, // path of parrot.
20000, // 20 seconds (duration)
true // Loop mode.
);
});

Support

Now follow() function is supported in r9 dev version which is currently on github.

Result

--

--

Alexander Buzin
WhitestormJS Framework

🚀 Technical founder & startup enthusiast. 10+ years in the IT industry. Featured on hackernoon & TechCrunch