Reader small image

You're reading from  Learn Three.js - Third Edition

Product typeBook
Published inAug 2018
Reading LevelIntermediate
PublisherPackt
ISBN-139781788833288
Edition3rd Edition
Languages
Right arrow
Author (1)
Jos Dirksen
Jos Dirksen
author image
Jos Dirksen

Jos Dirksen has worked as a software developer and architect for almost two decades. He has a lot of experience in many technologies, ranging from backend technologies, such as Java and Scala, to frontend development using HTML5, CSS, JavaScript, and Typescript. Besides working with these technologies, Jos regularly speaks at conferences and likes to write about new and interesting technologies on his blog. He also likes to experiment with new technologies and see how they can best be used to create beautiful data visualizations. Previously, Jos has worked in many different roles in the private and public sectors, ranging from private companies such as ING, ASML, Malmberg, and Philips to organizations in the public sector, such as the Department of Defense and the Port of Rotterdam.
Read more about Jos Dirksen

Right arrow

Expanding your first scene with animations

If we want to animate the scene, the first thing that we need to do is find some way to re-render the scene at a specific interval. Before HTML5 and the related JavaScript APIs came along, the way to do this was using the setInterval(function,interval) function. With setInterval, we could specify a function that, for instance, would be called every 100 milliseconds. The problem with this function is that it doesn't take into account what is happening in the browser. If you were browsing another tab, this function would still be fired every couple of milliseconds. Besides that, setInterval isn't synchronized with the redrawing of the screen. This can lead to higher CPU usage, flickering, and generally poor performance.

Introducing requestAnimationFrame

Modern browsers luckily have a solution for that with the requestAnimationFrame function. With requestAnimationFrame, you can specify a function that is called at an interval. You, however, don't define this interval. This interval is defined by the browser. You do any drawing you need to do in the supplied function, and the browser will make sure it is painted as smoothly and efficiently as possible. Using this is really simple (the complete source can be found in the 04-04.js file); you just create a function that handles the rendering:

function renderScene() { 
  requestAnimationFrame(renderScene); 
  renderer.render(scene, camera); 
} 

In this renderScene function, we call requestAnimationFrame again, to keep the animation going. The only thing we need to change in the code is that instead of calling renderer.render after we've created the complete scene, we call the renderScene function once to initiate the animation:

... 
document.getElementById("webgl-output") 
  .appendChild(renderer.domElement); 
renderScene(); 

If you run this, you won't see any changes yet compared to the previous example because we haven't animated anything yet. Before we add the animation, though, we introduce a small helper library that gives us information about the frame rate the animation is running at. This library, from the same author as Three.js, renders a small graph that shows us information about the rate at which the scene is rendered.

To add these statistics, we first need to include the library in the <head> element of the HTML, as follows:

<script type="text/javascript" src="../../libs/util/Stats.js"></script>

The only thing left to do is initialize the statistics and add them to the page:

function initStats(type) {

var panelType = (typeof type !== 'undefined' && type) && (!isNaN(type)) ? parseInt(type) : 0;
var stats = new Stats();

stats.showPanel(panelType); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild(stats.dom);

return stats;
}

This function initializes the statistics and, based on the passed in type variable renders the frames per second, the time it took to render the frame, or the amount of allocated memory. At the beginning of our init() function, we'll call this function, and we've got stats enabled, as follows:

function init(){ 
 
  var stats = initStats(); 
  ... 
} 
Since this is something we want to add to each example, we don't add the initStats function to the sources of our examples, but this function, together with other useful helper functions, are added to the util.js file.

This file is included in the header of the HTML pages as follows:

<script type="text/javascript" src="../js/util.js"></script>

The only thing left to do now is to tell the stats object when we're in a new rendering cycle. We do this by adding a call to the stats.update function in our renderScene function, as follows:

function renderScene() { 
  stats.update(); 
  ... 
  requestAnimationFrame(renderScene); 
  renderer.render(scene, camera); 
} 

If you run the code with these additions, you'll see the statistics in the upper left-hand corner, as shown in the following screenshot:

60 FPS (49-60)

Animating the cube

With requestAnimationFrame and the statistics configured, we've got a place to put our animation code. In this section, we'll expand the renderScene function with code that will rotate our red cube around all of its axes. Let's start by showing you the code:

function renderScene() { 
  ... 
  cube.rotation.x += 0.02; 
  cube.rotation.y += 0.02; 
  cube.rotation.z += 0.02; 
  ... 
  requestAnimationFrame(renderScene); 
  renderer.render(scene, camera); 
} 

That looks simple, right? What we do is that we increase the rotation property of each of the axes by 0.02 every time the renderScene function is called, which shows up as a cube smoothly rotating around all of its axes. Bouncing the blue ball isn't much harder.

Bouncing the ball

To bounce the ball, we once again add a couple of lines of code to our renderScene function, as follows:

  var step=0; 
  function renderScene() { 
    ... 
    step+=0.04; 
    sphere.position.x = 20 + 10*(Math.cos(step)); 
    sphere.position.y = 2 + 10*Math.abs(Math.sin(step)); 
    ... 
    requestAnimationFrame(renderScene); 
    renderer.render(scene, camera); 
  } 

With the cube, we changed the rotation property; for the sphere, we're going to change its position property in the scene. We want the sphere to bounce from one point in the scene to another with a nice, smooth curve. This is shown in the following diagram:

For this, we need to change its position on the x axis and its position on the y axis. The Math.cos and Math.sin functions help us create a smooth trajectory using the step variable. I won't go into the details of how this works here. For now, all you need to know is that step+=0.04 defines the speed of the bouncing sphere. In Chapter 8, Creating and Loading Advanced Meshes and Geometries, we'll look in much more detail at how these functions can be used for animation, and we'll explain everything. Here's how the ball looks in the middle of a bounce:

60 FPS (1-60)

Before wrapping up this chapter, we must add one more element to our basic scene. When working with 3D scenes, animations, colors, and properties like that, it often requires a bit of experimenting to get the correct color or speed. It would be very easy if you could just have a simple GUI that allows you to change these kinds of properties on the fly. Luckily, there is!

Previous PageNext Page
You have been reading a chapter from
Learn Three.js - Third Edition
Published in: Aug 2018Publisher: PacktISBN-13: 9781788833288
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Jos Dirksen

Jos Dirksen has worked as a software developer and architect for almost two decades. He has a lot of experience in many technologies, ranging from backend technologies, such as Java and Scala, to frontend development using HTML5, CSS, JavaScript, and Typescript. Besides working with these technologies, Jos regularly speaks at conferences and likes to write about new and interesting technologies on his blog. He also likes to experiment with new technologies and see how they can best be used to create beautiful data visualizations. Previously, Jos has worked in many different roles in the private and public sectors, ranging from private companies such as ING, ASML, Malmberg, and Philips to organizations in the public sector, such as the Department of Defense and the Port of Rotterdam.
Read more about Jos Dirksen