Three.js – Animated Objects

Three.js – Animated Objects

0 59620
Three.js – Animated Objects

Animation in 3D space – one of the integral and exciting processes. Animation gives life to your static scene. I think you have already thought about the animation of objects when working with three.js. Yes, animate objects is possible with functions of three.js, we can change the position, size, rotation, and other properties of objects (and their children) in real-time. However, this becomes problematic if we want to change the properties of tens or even hundreds of related objects at once, especially when it comes to three-dimensional animation of the (rigged) characters. In this case, much easier to animate the 3d model in a special editor, and then export the model into a suitable format for loading into three.js. In this lesson we will look at a variety of three-dimensional editors, and we learn how to download our animated models in three.js scene.

During my research and experience, I found that only two file formats could contain the animation (to be used in three.js): Json and Dae.

Live Demo 1
Live Demo 2
Live Demo 3

Before we start our discussion, you may test our demos. In the first demo, we load Json model, last two demos – Dae models.

3D editors and experience

The following 3D programs are installed on my computer:

  • 3ds Max Design 2014 (additionally, a special plugin to export models into Json was installed for the 3DS Max)
  • Poser Pro 2014
  • Unity
  • Blender (additionally, a special plugin to export models into Json was installed for the Blender)

Well, first of all, I downloaded a bunch (more than 20) of various models in different formats. There were different models: static and animated. I was going to use these models to import in the installed 3D editors.

Poser Pro 2014

This program, seemed me like a very friendly program to work with 3D characters. There are many ready models in ‘Library’, and you can handle with the model easily, using your mouse. After, you can export your result to Collada (dae). First window offers to select ‘Export Range’. Then – Export Options. I tried various options, but unfortunately, all my attempts to load the exported dae file into three.js failed. It always gave me the following error: Uncaught TypeError: Cannot read property ‘add’ of undefined (three.min.71.js:365)

But, when I tried to import this file in Blender, the animation was here. I tried to re-export it into dae again (in Blender), but it didn’t work. I also tried to export that model into Json and load into scene – this worked, however the animation was corrupted. Thus I decided to put away this program. It didn’t want to work properly by some reason.

Poser

Unity

This is a bit difficult-to-use program. It allows you to import models (as assets), make some changes with the model, and export to dae (Collada Export). I tried with several models, however after I exported the models into dae, the models failed to load in three.js. It gave the following error: Uncaught TypeError: Cannot read property ‘elements’ of null (three.min.71.js:44). Thus I decided to put this program away, too.

Unity

3ds Max Design 2014

The program has a pretty friendly interface, but it could be complex, because of many functions and properties. 3ds Max supports many 3D formats, so you can export/import most of models. However, nearly always, when I tried to load the result models (in DAE format), I received the following error:

Uncaught TypeError: Cannot read property ‘initialized’ of undefined (three.min.71.js:696)

I also tried to use the installed plugin (ThreeJsExporter), but it also didn’t give me the desired result.

Blender

From the first view it looks like this program is the most low level editor. Like 3DS Max, it has a lot of functions, but this is much lighter and free (other programs that we used require a paid license). But, for a beginner, it could be difficult to learn this program. Especially after all the programs we tried before – all of them have friendly graphic interface, but there is no the toolbar with buttons in the Blender. Sometimes it is really difficult to find something here. However, this program finally does what we need. It also supports various 3d file formats, like dae/fbx (that support the animation).

Blender - model

If you export to Collada/dae, I recommend to use the following properties:

Blender - dae

If you export to Json, use the following properties:

Blender - json

Of course, not any models could be easily exported without any problem, but most of them. The initial model should be properly rigged with bones.

Besides that, if you notice, that your model looks like that (after exporting):

Variant 1

So, the model is currupted. To solve this situation, I recommend the following steps:

1) Click right mouse button on a nearest bone (so you will select it), then press twice ‘A’ button (to select all bones), switch to Pose Mode.

2) Goto ‘Pose’ -> ‘Clear Transform’ -> ‘All’.

Step 1

3) Then switch to ‘Object Mode’, select your model in any place, then press twice ‘A’ button again (to select the whole model), then: CTRL-A -> Location, CTRL-A -> Position, CTRL-A -> Scale

After, try to export to DAE (or Json) again. After these actions, the model usually works fine in three.js. If not – try another initial model (dae / fbx). This method worked for me with several animated models, but not with all downloaded models. Now, let’s start with coding. First of all, create a new html file and put the following code:

index.html

<!DOCTYPE html>
<html lang="en" >
  <head>
    <meta charset="utf-8" />
    <meta name="author" content="Script Tutorials" />
    <title>WebGL With Three.js - Lesson 11 - Animated Objects | Script Tutorials</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <link href="css/main.css" rel="stylesheet" type="text/css" />
  </head>
  <body>
    <script src="js/three.min.71.js"></script>
    <script src="js/THREEx.WindowResize.js"></script>
    <script src="js/OrbitControls.js"></script>
    <script src="js/stats.min.js"></script>
    <script src="js/ColladaLoader.js"></script>
    <script src="js/script.js"></script>
  </body>
</html>

This simple code loads all the necessary libraries.

Skeleton of the scene

Now, create ‘js’ directory, and empty ‘script.js’ in the directory. Put the following code into this file:

js/script.js

var lesson11 = {
  scene: null, camera: null, renderer: null,
  container: null, controls: null,
  clock: null, stats: null,
  init: function() {
    // Create main scene
    this.scene = new THREE.Scene();
    this.scene.fog = new THREE.FogExp2(0xc8e0ff, 0.0003);
    var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
    // Prepare perspective camera
    var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 1, FAR = 1000;
    this.camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
    this.scene.add(this.camera);
    this.camera.position.set(100, 0, 0);
    this.camera.lookAt(new THREE.Vector3(0,0,0));
    // Prepare webgl renderer
    this.renderer = new THREE.WebGLRenderer({ antialias:true });
    this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
    this.renderer.setClearColor(this.scene.fog.color);
    // Prepare container
    this.container = document.createElement('div');
    document.body.appendChild(this.container);
    this.container.appendChild(this.renderer.domElement);
    // Events
    THREEx.WindowResize(this.renderer, this.camera);
    // Prepare Orbit controls
    this.controls = new THREE.OrbitControls(this.camera);
    this.controls.target = new THREE.Vector3(0, 0, 0);
    this.controls.maxDistance = 150;
    // Prepare clock
    this.clock = new THREE.Clock();
    // Prepare stats
    this.stats = new Stats();
    this.stats.domElement.style.position = 'absolute';
    this.stats.domElement.style.left = '50px';
    this.stats.domElement.style.bottom = '50px';
    this.stats.domElement.style.zIndex = 1;
    this.container.appendChild( this.stats.domElement );
    // Add lights
    this.scene.add( new THREE.AmbientLight(0xFFFFFF));
    // Load Json model
    this.loadJsonModel();
    // Load Dae model
    // this.loadDaeModel();
  },
  loadJsonModel: function() {
  },
  loadDaeModel: function() {
  }
};
// Animate the scene
function animate() {
  requestAnimationFrame(animate);
  render();
  update();
}
// Update controls and stats
function update() {
  var delta = lesson11.clock.getDelta();
  lesson11.controls.update(delta);
  lesson11.stats.update();
  THREE.AnimationHandler.update(delta);
}
// Render the scene
function render() {
  if (lesson11.renderer) {
    lesson11.renderer.render(lesson11.scene, lesson11.camera);
  }
}
// Initialize lesson on page load
function initializeLesson() {
  lesson11.init();
  animate();
}
if (window.addEventListener)
  window.addEventListener('load', initializeLesson, false);
else if (window.attachEvent)
  window.attachEvent('onload', initializeLesson);
else window.onload = initializeLesson;

This is basic code to run the scene.

loadJsonModel

The following code is used to load Json models:

  loadJsonModel: function() {
    // Prepare JSONLoader
    var jsonLoader = new THREE.JSONLoader();
    jsonLoader.load('models/girl.json', function(geometry, materials) {
      materials.forEach(function(mat) {
        mat.skinning = true;
      });
      // Prepare SkinnedMesh with MeshFaceMaterial (using original texture)
      var modelMesh = new THREE.SkinnedMesh(
        geometry, new THREE.MeshFaceMaterial(materials)
      );
      // Set position and scale
      var scale = 40;
      modelMesh.position.set(0, -20, 0);
      modelMesh.scale.set(scale, scale, scale);
      // Prepare animation
      var animation = new THREE.Animation(
        modelMesh, geometry.animations[0],
        THREE.AnimationHandler.CATMULLROM
      );
      // Add the mesh and play the animation
      lesson11.scene.add(modelMesh);
      animation.play();
    });
  }

After the model file is loaded, we set ‘skinning’ to ‘true’ for all children materials. Then we create THREE.SkinnedMesh with THREE.MeshFaceMaterial (to support original materials), then we scale and set position the model, prepare the animation, and finally – add the model into our scene and play the animation.

The following code is used to load Dae models:

  loadDaeModel: function() {
    // Prepare ColladaLoader
    var daeLoader = new THREE.ColladaLoader();
    daeLoader.options.convertUpAxis = true;
    daeLoader.load('models/robot.dae', function(collada) {
      var modelMesh = collada.scene;
      // Prepare and play animation
      modelMesh.traverse( function (child) {
        if (child instanceof THREE.SkinnedMesh) {
          var animation = new THREE.Animation(child, child.geometry.animation);
          animation.play();
        }
      } );
      // Set position and scale
      var scale = 2.5;
      modelMesh.position.set(0, -20, 0);
      modelMesh.scale.set(scale, scale, scale);
      // Add the mesh into scene
      lesson11.scene.add(modelMesh);
    });
  }

As you see, the code is a bit different then ‘loadJsonModel’. After we load the model, we traverse all it’s children and start playing the animation. Then we set the position and scale, and add the model mesh to the scene.

The lesson is finished. See you in the next tutorial.


Live Demo 1
Live Demo 2
Live Demo 3

[sociallocker]

download in package

[/sociallocker]

SIMILAR ARTICLES

Understanding Closures

0 23000

NO COMMENTS

Leave a Reply