UPDATE: Originally this tutorial was written for THREE.js r56 and Blender 2.65 but lately I’ve tested it with THREE.jsr60 and Blender 2.68a and it worked (actually it also worked with THREE.js versin “r61dev.”. whatever it means), so I believe that it works for the versions in between also.
UPDATE 2: Currently THREE.js exports multiple actions using blender exporter, so this tutorial in not suitable for exporters for THREE.js versions r62 and higher. It should work well with versions r56 up to r61
Today I’ve faced a rather difficult problem to solve. Creating model in Blender, animating it with armature and exporting the animation to THREE.js (r56) JSON format.
I was working on for 2 days now and it was really a harsh job to be done, especially that THREE.js is still in alpha version and a lot of features are not stable and fully reliable. So now I’m gonna explain how to perform the mentioned task.
For this I’m using Blender 2.65, and exporter for this version found in THREE.js package (https://github.com/mrdoob/three.js/).
In this tutorial I assume that you know JavaScript at intermediate level and are familiar with Blender basics.
The animation will be made of 2 cubes traveling up and down.
The Blender part
Creating objects and armature
- Start Blender, delete the default cube.
- Add two cubes and place them side by side.
- Select one of the cubes, and press Shift+S and select “cursor to selected” This will let us add an armature to the world in correct place.
- Join these cubes meshes – select them both and press Ctrl+J.
Before continuing, you should know that:
There could be only one armature responsible for rigging the objects and many objects controlled by its bones
This is because if you add another armature and animate its bones you will end up with more than one action in Blender and THREE.js exports only one (the first) it founds in Blender file
- Add an armature bone: press Shift+A in the 3d view and select Armature->Single bone.
Now in the wireframe view (press Z to switch between display modes) you should see the bone “in” the cube.
- Now we have to create the bones setup. Go to edit mode with the armature, select the first bone and duplicate(Shift+D) and grab the new bone so the result would look like so:
Having those let’s go on to parenting.
The key to understand skeletal animation and skinning in Blender is the following rule:
The vertices that are to be moved by a bone have to be assigned to a vertex group which name is the same as the name of the bone responsible form moving them.
This is the only requirement for THREE.js to know which vertices are belonging to which bone, when exporting to JSON format, no other information is required – the skinned mesh doesn’t require to be parented to the armature at export time. In case with Blender the parenting must occur to see the changes when moving the bones and actually creating the animation but THREE.js ignores that information.
Now we’re at the point where we can do one of two things: we can parent the boxes mesh to the armature with automatic computing of the vertex weights or we can create vertex groups manually and assign vertices to them by hand.
In practice the decision is highly depending on what is going to be rigged: if you have some simple technical meshes do it manually, if you have a highly complicated organic mesh – you will want to do it automatically.
But.. the first method is a little more risky because the automatic creation of vertex groups and computation of their weights may be inaccurate and..
THREE.js demands all the vertices of a skinned mesh to be assigned to vertex groups and all vertex groups to be named after the corresponding bone.
In case of automatic parenting the vertex groups are created and weights calculated. The problem may be that some vertices will not be assigned to vertex groups. So in this case it’ll be likely that you’ll need to correct the results manually if some of the vertices are out.
The second method – of manually assigning vertices to vertex groups may be tedious and you can make a mistake while assigning. In this case you will need to take care of more things
In this tutorial I will show you both methods because they can be both usefull.
Naming bones and vertex groups
This is very important rule, and you should stay with it if you don’t want to get really frustrated. The matter has to do with a specific bug either on THREE.js exporter or inside the framework script. This bug doesn’t takes into account that the name of a vertex group or a bone may start with a number. So clearly:
The names of bones and vertex groups can’t start with a number
The recomended naming convention is to use only letters and underscores, but numbers are also allowed but not in the first place. So:
- this is incorrect: “1st_floor”
- this is correct: “first_floor”
- and this is also correct: “floor_1st”
Parenting with “Armature deform with automatic weights”
- Unselect everything in the 3d space. The select the boxes(RMB) and “add select” the armature (Shift+RMB)
- Now press Ctrl+P and select “Armature deform with automatic weights”
At this point you could start making animation – moving the bones and keying.
But before doing you should check if every vertex is attached to a vertex group. This will most probably save a lot of problems further as I mentioned before.
- To do so you need to select the cubes, go to the edit mode and switch to “object data” view in “properties” panel. This is what you should see:
In the vertex groups panel now are two groups: Bone and Bone.001, they were created automatically when we were parenting the cubes mesh to the armature bones..
- To check if the vertices belong to correct groups: first unselect any selected vertices with “A” on the keyboard.
- Then click one of the group and press “select” in the “vertex groups” subpanel. You should see the vertices of a box selected. Rotate around and check if all vertices of a cube are selected.
- Repeat the process for the other group (steps 2 and 3 above – - deselect vertices and select the other vertex group).
If all vertices in the object made of two cubes belong to one of the vertex groups you can start animating the bones in pose mode. If not you will have to assign the spare vertices to the vertex group. I won’t cover this in step by step tutorial. I think you will figure it out (or already are able to do so) after explaining how to manually create vertex groups related to the bones and assign vertices to these groups.
Manual creation of vertex groups
The other way, which may be simpler in this case with two cubes in one mesh is to manually create the vertex groups and assign vertices to them.
This method would be especially usefull when rigging non organic, technical shapes, where the vertices are easy to select. The usefull way to select them is “select linked’ tool to select vertices linked to each other.
Suppose we are at the point where the two bones in our example are not yet parented or related in any other way to the two cubes – single object.
- First check the names of the bones of the armature. Go to the object mode, select the armature by clicking at one of the armature’s bone and go to edit mode again and select the bone the name you want to know. Depending on the bone yoy’ve selected you should see it’s name in the lower left corner of the screen:
There you can see the name of the armature you are currently editing and the name of the selected bone. Remember the names. - Enter the “object data” panel in the “properties” window. You should see “vertex groups” panel with no groups.
- We need to create the groups with the same names as the names of bones rigging their vertices. Press the “+” button. You should see a new group appeared. Select the group and enter a new name for it and press “enter” to confirm the new name:
- Now we need to assign vertices to the groups. We have to select the vertices to be rigged by a particular bone, select the group of the bone in the vertex groups panel and click “assign” button.
- Repeat process for the “Bone” vertex group.
Parenting the cubes to armature with “Armature” relation
If you’ve choosen the manual way you will see now that moving the bones in pose mode doesn’t makes the cubes move, so we can’t do the animation. The reason is that there is no in-Blender relationship between those. THREE.js would deal with it by using vertex groups names and bones names but in Blender this isn’t enough.
Thus we have to parent the object with cubes to the armature with “armature” relation.
- Select the cubes in object mode, go to “object” menu in “properties” panel. In relations subpanel you should see “relations” subpanel:
- Click on the parent box and select the armature object, then click the dropdown below it and select “armature”. The result should look like so:
If after parenting the cubes are not in place with bones, go to object mode, select the object with cubes and align it to the bones.
Now we can start animating the bones.
Animation
The animation here means that we will be keyframing the bones in pose mode. At the beginning one key information:
Every bone that is related to the model has to have at least one keyframe
Wihout this you should expect incorrect results when running animation in THREE.js.
The other thing you should be aware of is that
The animation will start at frame where first keyframe was found and end at the frame where last keyframe was found.
This means that you can have bones with one keyframe but the animation will span wider if you have other bone with two keyframes far away from each other. The keyframes are searched globally, which means that the animation will span at the earliest keyframe found in the file and end in the last found, which may be on a different bone.
Knowing that we can start creating animation:
- Select the armature and go to pose mode
- Select the first bone, move to frame 1 on the timeline . Place the cursor in 3d view and insert a keyframe (“I”). Select “LocRotScale”.
- Move to frame 50 on the timeline with the bone seleced. Move the bone up and insert a keyframe.
- Go to frame 100, move bone back to original position and insert a keyframe.
- Deal with the second bone. Go back to frame 1 select second bone, move it up and insert a keyframe.
- Go to frame 50 move the bone down and insert a keyframe
- Go to frame 100 move the bone to the same position as in frame 1 and insert a keyframe
To see most similar animation in Blender to what will be happening in THREE.js you can move to frame 100, move the mouse cursor over the timeline window and press “E”. This will set the end of animation to frame 100.
Now playing the animation (Alt+A) you should see cubes moving up and down.
To see what we are talking about here is a version rendered in Blender:
Scaling and unparenting and checking animations.
Before actually exporting you have to do some more things.
Keep in mind that..
you won’t be able to scale anything after exporting is done.
In my experience I had a problem when trying to change scale in JSON file. The pivot points were simply in wrong place, so scaling models in THREE.js will probably break the rigging.
And the key matter:
the rigged object must be at its rest pose when exporting
Which may mean that you will have to do one of the following:
unparent the skinned(rigged) object from the armature “Armature” parent
and if you were working with rigging using “Armature” modifier
remove the armature modifier from the rigged object
If you’ve done so, playing the animation (with Alt+A ) will show only the bones moving and the mesh as unchanged.
The rest pose of course may be at some frame, and if you know that frame, You have to export your model at this frame.
This is very important because if you will not do so the model will be offset in THREE.js in a matter that’s relative to it’s “rest pose”
Another important step is to:
check if the animation you are exporting is the one you want.
Blender keeps track of many animations – called “actions”. In case of THREE.js – only one animation can be exported to .js (JSON) file. This actually means that the only animation present in the .blend file has to be the one you want, otherwise the THREE.js exporter may confuse things badly.
There is no way of having more than one action(animation) in THREE.js exported from Blender at the current time of writing (THREE.js release r56)
To make it happen you need to delete unwanted actions from the Blender internal datablock structure. In a fresh files, where there was only one animation done there’s no such a need.
If you are curious – the real problem is that THREE.js exporter doesn’t export all animations or the current one, but only the first animation found in currently edited Blender file, which can be an old animation, currently unused. Threre may be a way to make the animation we want first, but for the sake of simplicity lets go and delete the animations we don’t need.
To explain this I’ve made some “fake” empty actions in this example. So, to check if there any spare “acitons”:
- With the armature selected go to DopeSheet window:
- Select action editor:
- In the header you should see a dropdown for available actions, click on it and check if there are unused action datablocks, which has a 0 number to the left In this example there are four unused action datablocks.
If there are any unused action datablocks you have to manually delete them. This is done by reloading the current file. To do so:
- First save the file
- Go to File menu, click Open recent and open the file you are already editing.
The unused datablocks should disappear.
There is also another situation: when you created many actions for example by keyframing two or more different objects. You need to select those object and in DopeSheet action editor – unlink them by pressing the “X” button next to the available actions dropdown. Then reload the file as above.
Reseting position, rotation and scale
The last thing and probably the most important for the happy ending is to reset location, rotation and scale of the mesh and the armature. This step is not required if the mentioned are at their defaults. This must apply for the mesh and the armature. To do so select the mesh and press CTRL+A, then select “location”. Repeat this for “rotation” and “scale”. Do the same for armature. Now you’re (by chance of 99%) done.
Exporting
- Go to object mode and select everything (“A” on keyboard)
- Go to the File menu, select Export -> THREE.js
- In the exporting window select the name of the file and it’s path.
- The THREE.js export window should look like following:
- Keep in mind that the following options must be enabled: “skinning”, “bones” and “skeletal animation”.
- Export the JSON file.
Summary of Blender part:
The checklist:
- The object(s) has every vertex assigned to at least one vertex group
- Each vertex group has a name corresponding to the name of bone that controls it
- The correct animation is exported
- Every single bone must have a keyframe
- The animation starts at first keyframe found and ends at last keyframe
- The model is in its “rest pose”
- No spare animations “actions” are registered in Blender so that only one is to be exported
- The location/rotation and scale of mesh and armature are reset
Known limitations:
- Only one action can be exported.
Advantages over morph animations:
- Low file sizes
Blender example file to download (based) on this tutorial:
Blender file ready to export for three.js
The exported file for three.js:
Json file ready to load in three.js
Three.js
To display the model animation there are some things needed to be done. First we need correct setup for the scene, along this we need to load model by:
var loader = new THREE.JSONLoader();
loader.load("animation.js", createSkinnedMesh)
Create a SkinnedMesh instance based on geometry and materials loaded from the JSON file and enable skinning on its MeshFaceMaterial materials collection:
function createSkinnedMesh(geometry, materials) { skinnedMesh = new THREE.SkinnedMesh(geometry, new THREE.MeshFaceMaterial(materials)); enableSkinning(skinnedMesh); init(); } function enableSkinning(skinnedMesh) { var materials = skinnedMesh.material.materials; for (var i = 0,length = materials.length; i < length; i++) { var mat = materials[i]; mat.skinning = true; } }
At the end we need to add the SkinnedMesh to the scene, push animation data of its geometry to the THREE.AnimationHandler and finally create Animation instance and play it with play() method.
scene.add(skinnedMesh); THREE.AnimationHandler.add(skinnedMesh.geometry.animation); animation = new THREE.Animation(skinnedMesh, "ArmatureAction", THREE.AnimationHandler.CATMULLROM) animation.play();
Somewhere in the application we need to run the application animation loop so the last thing to do is to update the animation in it:
animation.update(deltaTimeMS); // deltaTimeMS - delta time in milisecond since last update loop execution
The complete example file:
The html file with animation explains more. It is populated with comments relating the animation stuff, you can download it here:
THREE.js scene with skeleton animated model.
The complete package
(ZIP with Blender model, JSON model, and Example scene):
Tutorial package.
Summary and notes:
This tutorial covered the basics concepts of rigging for THREE.js it deals with one object parented to one armature. Also it doesn’t covers the skin weights topic.