Animation with Morph Targets
Learn how to create animation using morph targets and use different functions to control animations.
Morph targets
Morph targets are the most straightforward way of defining an animation. We define all the vertices for each important position (also called keyframes) and tell Three.js to move the vertices from one position to the other.
We’ll show how to work with morph targets using two examples.
In the first example, we’ll let Three.js handle the transition between the various keyframes (or morph targets, as we’ll call them from now on).
In the second one, we’ll do this manually.
Keep in mind that we are only scratching the surface of what is possible with animations in Three.js. As we’ll see in this lesson, Three.js has excellent support for controlling animations, supports syncing of animations, and provides ways to smoothly transition from one animation to another.
Animation with a mixer and morph targets
Before we dive into the examples, first, we’ll look at the three core classes that we can use to animate with Three.js. Later in this lesson, we’ll show all the functions and properties provided by these objects:
THREE.AnimationClip
: When we load a model that contains animations, we can look in the response object for a field usually calledanimations
. This field will contain a list ofTHREE.AnimationClip
objects. Note that depending on the loader, an animation might be defined on aMesh
, aScene
, or be provided completely separately. ATHREE.AnimationClip
most often holds the data for a certain animation the model we loaded can perform. For instance, if we loaded a model of a bird, oneTHREE.AnimationClip
would contain the information needed to flap the wings, and another one might be opening and closing its beak.THREE.AnimationMixer
: It is used to control severalTHREE.AnimationClip
objects. It makes sure the timing of the animation is correct and makes it possible to sync animations together, or cleanly move from one animation to another.THREE.AnimationAction
: TheTHREE.AnimationMixer
itself doesn’t expose a large number of functions to control the animation, though. This is done throughTHREE.AnimationAction
objects, which are returned when we add aTHREE.AnimationClip
to aTHREE.AnimationMixer
(though we can get them at a later time by using functions provided byTHREE.AnimationMixer)
.
There is also an AnimationObjectGroup
, which we can use to provide the animation state not just to a single Mesh
but to a group of objects.
In the following example, we can control a THREE.AnimationMixer
and a THREE.AnimationAction
, which were created using a THREE.AnimationClip
from the model. The THREE.AnimationClip
objects used in this example morph a model into a cube and then into a cylinder.
Example: Morph targets
For this first morphing example, the easiest way to understand how a morph targets-based animation works is by executing the morph-targets.js
example in the playground below. The following screenshot shows a still image of this example:
Click the “Run” button to execute the above example:
const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') // const CopyWebpackPlugin = require('copy-webpack-plugin') const fs = require('fs').promises // we should search through the directories in examples, and use // the name from the files to generate the HtmlWebpackPlugin settings. module.exports = async () => { return { module: { rules: [ { test: /\.glsl$/i, use: 'raw-loader' } ] }, mode: 'development', entry: { 'chapter-9': './samples/chapters/chapter-9/morph-targets.js', }, output: { path: path.resolve(__dirname, 'dist'), filename: 'bundle.js', publicPath: '/', }, plugins: [ new HtmlWebpackPlugin(), ], experiments: { asyncWebAssembly: true }, devServer: { allowedHosts: 'all', host: '0.0.0.0', port: '3000', static: [ { directory: path.join(__dirname, 'assets'), publicPath: '/assets' }, { directory: path.join(__dirname, 'dist') } ] }, mode: 'development', } }
Note: ...