Babylon.js supports bones animations for your meshes.
Basically a skeleton (BABYLON.Skeleton
) contains a hierarchy of bones (BABYLON.Bone
). A bone is defined by a name, a parent (can be null) and a transformation matrix.
Here are the constructors:
BABYLON.Skeleton = function (name, id, scene)
BABYLON.Bone = function (name, skeleton, parentBone, matrix)
Inside a skeleton, bones can be found inside the skeleton.bones
array.
A bone can contain animations to animate its matrix
property.
A skeleton can be applied to a mesh through the mesh.skeleton
property.
You should note that babylon.js supports up to 4 bones influences per vertex.
The mesh must also have additional vertices data:
mesh.setVerticesData(matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind, false)
)mesh.setVerticesData(floatIndices, BABYLON.VertexBuffer.MatricesIndicesKind, false)
)The final matrix applied to each vertex is computed as follows:
finalMatrix = worldMatrix * (bonesMatrices[index0] * weight0 + bonesMatrices[index1] * weight1 + bonesMatrices[index2] * weight2 + bonesMatrices[index3] * weight3)
On low-end hardware, the maximum bones influences per vertex is reduced to 3.
Skeletons and bones can be loaded from .babylon files (FBX and Blender exporter support bones generation).
Here is a sample of how to load a boned mesh and how to launch skeleton animation:
BABYLON.SceneLoader.ImportMesh("him", "Scenes/Dude/", "Dude.babylon", scene, function (newMeshes, particleSystems, skeletons) {
var dude = newMeshes[0];
dude.rotation.y = Math.PI;
dude.position = new BABYLON.Vector3(0, 0, -80);
scene.beginAnimation(skeletons[0], 0, 100, true, 1.0);
}),
A complete running example can be found here
Bones and skeletons can be cloned (This is the case with the rabbits in the previous link).
Here is a sample of how to load and clone a mesh and its skeleton:
BABYLON.SceneLoader.ImportMesh("Rabbit", "Scenes/Rabbit/", "Rabbit.babylon", scene, function (newMeshes, particleSystems, skeletons) {
var rabbit = newMeshes[1];
rabbit.scaling = new BABYLON.Vector3(0.4, 0.4, 0.4);
shadowGenerator.getShadowMap().renderList.push(rabbit);
var rabbit2 = rabbit.clone("rabbit2");
var rabbit3 = rabbit.clone("rabbit2");
rabbit2.position = new BABYLON.Vector3(-50, 0, -20);
rabbit2.skeleton = rabbit.skeleton.clone("clonedSkeleton");
rabbit3.position = new BABYLON.Vector3(50, 0, -20);
rabbit3.skeleton = rabbit.skeleton.clone("clonedSkeleton2");
scene.beginAnimation(skeletons[0], 0, 100, true, 0.8);
scene.beginAnimation(rabbit2.skeleton, 73, 100, true, 0.8);
scene.beginAnimation(rabbit3.skeleton, 0, 72, true, 0.8);
}),
More complex models, such as the Dude, contain submeshes. When cloning you must iterate and clone the submeshes as well. Here is an example of how to clone a more complex model:
BABYLON.SceneLoader.ImportMesh("him", "Dude/", "dude.babylon", scene, function (newMeshes, particleSystems, skeletons) {
newMeshes[0].position = new BABYLON.Vector3(0, 0, 5); // The original dude
scene.beginAnimation(skeletons[0], 0, 120, 1.0, true);
dudes = [];
for (i = 0; i < 10; i++) { // 10 clones
var xrand = Math.floor(Math.random() * 501) - 250;
var zrand = Math.floor(Math.random() * 501) - 250;
var c = [];
for (j = 1; j < newMeshes.length; j++) {
c[j] = newMeshes[j].clone("c" + j);
c[j].position = new BABYLON.Vector3(xrand, 0, zrand);
c[j].skeleton = newMeshes[j].skeleton.clone();
scene.beginAnimation(c[j].skeleton, 0, 120, 1.0, true);
}
dudes[i] = c;
}
}
Starting with babylon.js v2.2, you can now attach a mesh to a bone (like a sword in the hand of your character for instance). To do so, just specify on which bone with the following code:
sword.attachToBone(skeleton.bones[34], character);
Please note that you also need to specify on which mesh the bone is currently applied.
You can find a sample here -
Starting with babylon.js v2.5, you can easily position, rotate, and scale bones.
Bones can be rotated and positioned in local space and world space. To move a bone in world space, you must pass BABYLON.Space.WORLD and the mesh to the method. If a space isn't passed to the method, then the bone is moved in local space (relative to the parent bone).
To rotate a bone around an axis, use the rotate function:
bone.rotate(axis, angle, BABYLON.Space.WORLD, mesh);
rotate world space demo -
rotate local space demo -
setAxisAngle, setYawPitchRoll, setRotation, or setRotationMatrix are used to rotate a bone to a specific rotation.
bone.setAxisAngle(axis, angle, BABYLON.Space.WORLD, mesh);
setAxisAngle world space demo 1 -
setAxisAngle local space demo 1 -
bone.setYawPitchRoll(yaw, pitch, roll, BABYLON.Space.WORLD, mesh);
demo -
bone.setRotation(rotation, BABYLON.Space.WORLD, mesh);
demo -
bone.setRotationQuaternion(quat, BABYLON.Space.WORLD, mesh);
demo -
bone.setRotationMatrix(rotMat, BABYLON.Space.WORLD, mesh);
demo -
Use getRotation or getRotationToRef to get the Vector3 rotation of a bone.
var rotation = bone.getRotation(BABYLON.Space.WORLD, mesh);
var rotation = BABYLON.Vector3.Zero();
bone.getRotationToRef(BABYLON.Space.WORLD, mesh, rotation);
demo -
Use getRotationQuaternion or getRotationQuaternionToRef to get the Quaternion rotation of a bone.
var rotationQuaternion = bone.getRotationQuaternion(BABYLON.Space.WORLD, mesh);
var rotationQuaternion = BABYLON.Vector3.Zero();
bone.getRotationQuaternionToRef(BABYLON.Space.WORLD, mesh, rotationQuaternion);
demo -
To change the position of a bone, you can rotate the parent bone, or you can leave the parent where it is and directly modify the position of the bone.
One way to do this is by translating the bone from its current position.
bone.translate(x, y, z, BABYLON.Space.WORLD, mesh);
demo -
If you need to set the bone to a specific location, use setPosition.
bone.setPosition(pos, BABYLON.Space.WORLD, mesh);
demo 1 -
To get the position of a bone, use getPosition or getPositionToRef.
var pos = bone.getPosition(BABYLON.Space.WORLD, mesh);
var pos = BABYLON.Vector3.Zero();
bone.getPositionToRef(BABYLON.Space.WORLD, mesh, pos);
demo -
You can scale a bone on the local x, y, z axes of the bone.
bone.scale(scaleX, scaleY, scaleZ);
demo -
The setScale function is used to set a bone to a certain scale value.
bone.setScale(scaleX, scaleY, scaleZ);
setScale is used in this demo -
The last parameter of scale and setScale is scaleChildren. Set scaleChildren to true if you want the scale to affect all the children / descendants of the bone.
demo -
Use getScale or getScaleToRef to get the current scale of a bone.
var scale = bone.getScale();
var scale = BABYLON.Vector.Zero();
bone.getScaleToRef(scale);
Babylon.js v2.5 also introduced Bone controllers.
The BoneLookController class is used to make a bone look toward a point in space.
With some bones, you will need to adjust the yaw, pitch, roll to get the bone to look in the right direction.
var target = BABYLON.MeshBuilder.createSphere();
var lookCtrl = new BABYLON.BoneLookController(characterMesh, headBone, target.position, {adjustYaw:Math.PI*.5, adjustPitch:Math.PI*.5, adjustRoll:Math.PI});
scene.registerBeforeRender(function(){
lookCtrl.update();
});
demo -
Inverse Kinematics (IK) is used to rotate a chain of bones so that the end of the first bone is at or closest to a target point. It's often used to rotate the limbs of a character.
The BoneIKController class is modeled after Blender's IK Bone Constraint, but is currently limited to 2 bones.
To use the BoneIKController, you must first create a target mesh and a pole target mesh.
var target = BABYLON.MeshBuilder.CreateSphere('', { diameter: 5 }, scene);
var poleTarget = BABYLON.MeshBuilder.CreateSphere('', {diameter: 2.5}, scene);
The bones will reach for the target mesh and the position of the pole target will determine how the joint between the bones will bend.
You most likely will want to parent your character to the pole target mesh so that it will move relative to the character.
poleTarget.parent = characterMesh;
The BoneIKController constructor takes the mesh of the character, the bone that will be closest to the target, the target, and an options param. The currently list of options are:
targetMesh, poleTargetMesh, poleTargetBone, poleTargetLocalOffset, poleAngle, bendAxis, maxAngle
var ikCtrl = new BABYLON.BoneIKController(characterMesh, forearmBone, {targetMesh:target, poleTargetMesh:poleTarget, poleAngle:Math.PI});
To use the controller, simply call the controller's update function before the scene is rendered.
scene.registerBeforeRender(function(){
ikCtrl.update();
});
demo -
If you used a mesh for a target, you can hide it by setting enabled to false.
target.setEnabled(false);
poleTarget.setEnabled(false);
Bones are computed using shaders by default. This allows better performance. But on low end devices shaders could be limited and not able to process bones. You can in this case ask Babylon.js to compute bones using CPU by setting mesh.computeBonesUsingShaders = false.