Skip to main content

The animation loop

So far, you've focused only on the mechanics of how a scene gets rendered. You'll now move on to when a scene gets rendered and updated.

The animation loop is an activity that your computer carries out every time it updates, or refreshes, the image on your display. With every update, your computer will ask your scene to perform any necessary updates and will then render a new image on your screen.

This process is akin to stop-motion animation used in film. A character model is set up, a picture is taken, the stage crew makes slight movements to the model, and takes a new picture. When these pictures are shown rapidly in sequence, the viewer sees an animated scene. The principle of the animation loop is similar, but it happens in real time.

Refresh rates and frame rates

Your computer redraws the content on your display many times every second. How often this happens is referred to as the refresh rate. You may have seen this term in the product data for monitors or televisions with values such as 60 Hz or 120 Hz. The unit Hz (Hertz) means number of times per second. So a display with a 60 Hz refresh rate will redraw the screen 60 times every second.

The frame rate of your animation is how many times your animation updates each second. The frame rate is sometimes the same value as the refresh rate, but it's independent. An animation's frame rate is affected by factors such as how much detail is in the animation and how powerful the computer rendering it is.

Why does this matter? You have to govern the frame rate of your animation so that it will render at the same speed on different displays. If you ignore the refresh rate, an animation that works as expected on a 60 Hz display will be twice as fast on a 120 Hz display.

Tracking time

Unfortunately, you can't simply ask what the refresh rate is or specify a desired frame rate using JavaScript. Instead, you'll need to know how many frames per second you intend to draw and keep track of the time the last frame was drawn.

This isn't as daunting as it sounds. Time in JavaScript is measured in milliseconds, so you need to calculate how many milliseconds there should be between frame updates. There are 1000 milliseconds in each second. Assume a target frame rate of 60 frames per second, and you can compute the frame time with the line of code below.

const MILLISECONDS_PER_FRAME = 1000 / 60;
SCREAMING_SNAKE_CASE

The name of the variable above is written in a format known as "screaming snake case." All the letters in the variable name are in uppercase, and words are separated by an underscore character. This convention is used by three.js to indicate values that won't change and are available to all the functions in a program. This tutorial uses this convention as well. When you see a variable named this way, it's intended for use anywhere in the project's code.

Next, you'll need a variable to keep track of how much time in milliseconds has passed since the last frame was rendered. Set this variable to zero since no frames have been rendered yet.

let lastFrameTime = 0;

Working with the animation loop

You now need a function that you can attach to the animation loop. Your web browser will call this function whenever your computer refreshes your display. When the browser calls the function, it passes a single parameter to it that indicates the time in milliseconds since your animation started.

As you learned earlier, you don't necessarily want to update your animation on each refresh. The function computes the elapsed time since it rendered the last frame and checks to see if that time is greater than or equal to the frame time you computed and stored in MILLISECONDS_PER_FRAME.

If enough time has passed, your animation will get updated, your scene will be re-rendered, and the value of lastFrameTime is set to the current time.

This sequence of events will repeat each time the animation loop calls this function.

Take note of the update function on the highlighted line in this code block. You'll create this function soon. Also note that you are making use of the scene, camera, and renderer that you created in the previous section.

function animate(animationTime) {
const elapsedTime = animationTime - lastFrameTime;

if (elapsedTime >= MILLISECONDS_PER_FRAME) {
update();
renderer.render(scene, camera);
lastFrameTime = animationTime;
}
}

Now you need to let the browser know to start calling this function as part of the animation loop. The following line of code will add the animate function to the animation loop and start rendering your scene.

renderer.setAnimationLoop(animate);
Functions can be parameters to other functions

Notice that the value passed to the function setAnimationLoop is not surrounded by quote marks. You are passing the function itself as a parameter rather than a string containing a function name.

The update function

When you created the animate function above, you made use of a function named update that you had not yet created. You'll find this function below, and, as you can see, it is empty.

function update() {
// Your project's animation code will go here.
}

As you progress through the project, you'll put any code that updates your scene in this function. Controlling the frame rate is something you'll do in every future project involving three.js. By moving the code that's specific to just one project into a separate function, you can now reuse the animate function in other projects. In fact, all the code you've assembled so far can be used with other projects as-is.