Practical 7 - Elements of solution

This page provides elements of solution for the (bonus) Skeletal Animation / Skinning practical.

Exercise 1: Skinning shader

Computing the skinning matrix in the vertex shader code is quite straightforward, if the role of each parameter is well understood (re-read the specification if needed).

mat4 skin_matrix = mat4(0);
for (int b=0; b < MAX_VERTEX_BONES; b++)
    skin_matrix +=  bone_weights[b] * bone_matrix[int(bone_ids[b])];

Results for the first cylinder animation should be:

_images/solution7_exo1_0deg.png _images/solution7_exo1_45deg.png _images/solution7_exo1_90deg.png

Note

Just completing this vertex shader is enough to load an animation file. For example, just run: ./viewer.py dino/Dinosaurus_roar.dae (only the sound is missing…).

Exercise 2: Smoothing

To modulate the contributions of the two bones, the bone_weights values must be adapted. Tune parameters to get a realistic simulation is clearly difficult. Here is an example with the following law (linear variation around the joint):

weight = np.clip(1-(2*x_c/sections-1/2), 0, 1)
bone_weights.append((weight, 1 - weight, 0, 0))
_images/solution7_exo2_0deg.png _images/solution7_exo2_45deg.png _images/solution7_exo2_90deg.png _images/solution7_exo2_0deg_w.png _images/solution7_exo2_45deg_w.png _images/solution7_exo2_90deg_w.png

Exercise 3: Adding a third bone

Here we propose to divide the cylinder in three parts:

#. the base consists in the left-hand sections, from the left extremity to the middle, just like in the previous exercise. #. the forearm is the right-hand sections except the last one. #. the hand is the last section, at the right extremity.

We will smooth things with a small joint at the vicinity between the base and the forearm.

Nodes are organized in a hierarchy: base is the root node, forearm is a child of the base, and hand is a child of the forearm node.

To do in your code:

  • create a KeyframeControlNode for the hand.

  • define the keyframes to animate each component of the transformation.

  • add the hand to the nodes hierarchy and to the bone_nodes list.

  • in the loop, add a third non-null index: bone_id.append((0, 1, 2, 0))

  • define the weights for each bone. The first three weights can be different than 0, and make sure the weights sum is equal to 1.

Example 1: naive rotation

In this first example, the base is fixed, the forearm is rotated by -25 degrees, and the hand is rotated by +45 degrees. If you simply put these rotations in your keyframes you will obtain:

_images/solution7_exo3_init.png _images/solution7_exo3_init_w.png _images/solution7_exo3_ko.png _images/solution7_exo3_ko_w.png

What is the problem? Well, all rotations are centered at the origin!

This is not a problem for the base / forearm joint because this joint actually lies at the origin. But this is clearly wrong for the hand joint.

Example 2: rotation center

The solution is similar to what we did in pratical 3 “hierarchichal modeling”: each part must be defined in its own referential where rotations are easily expressed around the origin. Then, objects must be correctly positioned with respect to their father referential.

First let’s redefine the x_c coordinates for the last section of the cylinder, to put them on 0 and 1:

if x_c < sections-1:
    vertices.append((x_c - sections/2, y_c, z_c))
else:
    # hand: last two x coords become 0, 1
    # (later translated by the KeyFrameControlNode)
    vertices.append((x_c - sections + 1, y_c, z_c))

The hand node must then be positioned with correct keyframes:

hand = KeyFrameControlNode(
    {0: (sections/2 - 1, 0, 0)},    # translation to the forearm extremity
    {0: quaternion(),
     2: quaternion_from_euler(45),  # rotation around the origin
     4: quaternion()},
    {0: 1})                         # no scaling here

Remember that transformations component are applied in the \(TRS\) order. The rotation is first applied around the origin and then the hand object is translated at the extremity of the forearm.

The result is as expected:

_images/solution7_exo3_ok.png _images/solution7_exo3_ok_w.png

Note

Now it’s you turn!

Move the position of first joint from the origin. Animate all parts including the base. And try to set weights so that some vertices depend from all three bones.