10/13

7.1. Animation

Animating a 3D scene can be seen as rendering several times the scene, while modifying each time some objects.

In order to obtain an appearance of a continuous animation, a new image should be displayed every 40ms at most (25 images per seconds). For small scenes and current graphics card, it is possible to render images in much less than 40ms. This display should be synchronized with the code running in a loop.

7.1. Animation loop with requestAnimationFrame

JavaScript proposes the function requestAnimationFrame enabling to perform such synchronization for animation purpose. It requests the browser to redisplay an image as soon as possible, and typically synchronize itself with the refresh rate of your screen.

The general principle to use requestAnimationFrame is the following

requestAnimationFrame( computeFrame );


function computeFrame( time ) {


    ... // handle computation at current time


    requestAnimationFrame( myAnimationFunction );
}
  • requestAnimationFrame is a function that receives another function as parameter (here called computeFrame, but its name is up to you). We call this parameter function a callback function).

  • The callback function passed as parameter automatically receives a parameter corresponding to the current time (similarly, you can name this parameter as you want).

  • The callback function can perform any computation related to the current frame, and then call itself requestAnimationFrame typically with himself as parameter to restart a new frame as soon as possible.

Example

The 3D scene of the previous example is now animated in the following one

[website, src, js]


// General variable storing the scene graph, and elements usefull to render the scene (camera, renderer, etc)
const sceneElements = {
    sceneGraph : null,
    camera     : null,
    renderer   : null,
};


// Three functions are called
//  1. Initialize an empty scene
//  2. Add elements within the scene
//  3. Render the scene
initEmptyScene(sceneElements);
load3DObjects(sceneElements.sceneGraph);

requestAnimationFrame( computeFrame );


function computeFrame( time ) {

    // Can extract an object from the scene Graph from its name
    const cylinder = sceneElements.sceneGraph.getObjectByName("rotatingCylinder");
    // Apply a small rotation increment of 0.07 radians
    cylinder.rotateOnAxis(new THREE.Vector3(1,0,0), 0.07 );

    // Render the scene
    render( sceneElements );

    // Call for the next frame
    requestAnimationFrame( computeFrame );

}

// ... Rest of functions



function load3DObjects(sceneGraph) {
    // ...
    const cylinderGeometry = new THREE.CylinderGeometry( ... )
    // ...

    // Give a name to the cylinder
    cylinderObject.name = "rotatingCylinder";
}