Skip to content

Instantly share code, notes, and snippets.

@roxlu
Last active June 4, 2020 01:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save roxlu/af986051e4668c3a6837 to your computer and use it in GitHub Desktop.
Save roxlu/af986051e4668c3a6837 to your computer and use it in GitHub Desktop.
Getting Skeleton Animation to work with OpenGL and the IQM file format.

Some braindumps about matrices and rotations

When use a Matrix4 and rotate it 90º around X-axis I get:

 1.00,  0.00,  0.00,  0.00
 0.00, -0.00, -1.00,  0.00
 0.00,  1.00, -0.00,  0.00
 0.00,  0.00,  0.00,  1.00

When I rototate a Quaternion 90º around X-axis I get:

 0.707107, 0.000000, 0.000000, 0.707107

Then when I convert this Quaternion back to a Matrix4 I get:

 1.00,  0.00,  0.00,  0.00
 0.00,  0.00,  1.00,  0.00
 0.00, -1.00,  0.00,  0.00
 0.00,  0.00,  0.00,  1.00

Why are some values negated now?

Answer

I have a #define HALF_PI 1.57079632679489661923 when I assigned it to a float and used that float with cos() the result is -0.0. This is because of loosing precision when assigning that value to a float. When I assign e.g. float hp = 1.57079 and pass that into cos() the result is 0.0. Though this isn't really a problem as -0.0 or 0.0 will result in the same value when multiplying.

Blender rotations & quaternions

Before I start, you need to know that Blender uses a right handed system with Z-up.

A quaternion like: -0.707107, -0.000000, -0.000000, 0.707107 Represents an -90º rotation around x. The matrix looks like:

1.00,  0.00,  0.00,  0.00
0.00,  0.00, -1.00,  0.00
0.00,  1.00,  0.00,  0.00
0.00,  0.00,  0.00,  1.00

When you have a bone, pointing up in Blender (default pos), the matrix is:

>>> bpy.data.armatures[0].bones[0].matrix_local

Matrix(((1.0, 0.0,  0.0, 0.0),
       (0.0, 0.0, -1.0, 0.0),
       (0.0, 1.0,  0.0, 0.0),
       (0.0, 0.0,  0.0, 1.0)))

Converting this to quaternion:

(0.707, 0.0, 0.0, 0707) (xyzw)

Per element:

>> bpy.data.armatures[0].bones[0].matrix_local.to_quaternion().x
0.7071068286895752

>>> bpy.data.armatures[0].bones[0].matrix_local.to_quaternion().y
0.0

>>> bpy.data.armatures[0].bones[0].matrix_local.to_quaternion().z
0.0

>>> bpy.data.armatures[0].bones[0].matrix_local.to_quaternion().w
0.7071068286895752

Example of GLM perspective matrix:


glm::mat4 pm = glm::perspective(45.0f, 1280.0f / 720.0f, 0.1f, 100.f);

 1.01,  0.00,  0.00,  0.00
 0.00,  1.79,  0.00,  0.00
 0.00,  0.00, -1.00, -0.20
 0.00,  0.00, -1.00,  0.00

Example of MathFu projection matrix (Right Handed)


perspective(pm, 45.0f, 1280.0f/720.0f, 0.1f, 100.0f, 1.0f);

 1.01,  0.00,  0.00,  0.00
 0.00,  1.79,  0.00,  0.00
 0.00,  0.00, -1.00, -0.10
 0.00,  0.00, -1.00,  0.00

Swapping Z-up with Y-up in general

From the link below:

Downvote me if I am wrong, but I don't see why people are recommending swapping y and z. That would make your coordinate system from being right handed to left handed. Try this yourself, swap the y and z, and reorient the axis so that x points right and y points up. You will see that z points the opposite direction from its original (away from the screen). The proper way is to rotate around the x-axis, which is swap y and z, and then invert the sign of the final z. I think the easier solution is to build your models with y value being up.

Source 1, gamedev.

As explained by "Stan_Pancakes" on #blender at freenode.

Stan_Pancakes:	roxlu, armature's oriented same as world: Z up. First bone's Y axis is looking "up": there's your 90 degree rotation (relative to armature object's rotation).
roxlu:	Stan_Pancakes .. so the bone local Y-axis is pointing up?
Stan_Pancakes:	roxlu, yes. Object data is stored in object's coordinate space. Vertices in meshes, bones in armatures, points in curves...
sciver:	roxlu for general reference, the bone's Y axis is always along the bone's length, from base to tail

So what's Stan_Pancakes saying here is that there are actually different spaces in which objects, vertices, bones, etc.. are stored. The meaning of X,Y,Z are different for these spaces. Objects/vertices are stored in blenders Z-up coordinate space, but bones are in Y-up. To understand what that means my brains need to do a bit of processing :) Bones are in "Y-up" .... hmm well, it does clarify when I tell you that the head-to-tail of a bone is pointing into the Y-axis. In the image below I've aligned the bone Y-axis with the Y-axis of blender-world-space:

Screen Shot 2015-05-21 at 21.45.59

When you create a model in Blender you use Z-up, so to align the head-tail of bone you make sure the bones are pointing "up" along the direction of your object (Z-axis). In the image below you can see how the bones are pointing "up" aligned with the Z-axis of the model. This means the bones have rotated -90 degrees around the X-axis.

Screen Shot 2015-05-20 at 23.02.40

Similar problem with possible solution

Left vs. Right handedness

The handedness defines where your Z-axis points to. Does the positive direction go towards you or away from you. There is a trick for this. Form a L with your thumb and index, your index finger pointing up. When you do this with your left hand, you can clearly read the letter "L", now, add your middle finger which will point into the direction of the positive Z-axis. When you do this with your right hand, you'll need to rotate your hand a bit to get the correct "L" shape. Your index fingex will be pointing towards you which means the positive direction goes to you face, and the negative direction away from you.

Thinks to know about handedness:

  • Handedness defines the direction of the Z-axis (negative away for LF, positive away for RH)
  • Handedness defines the direction of rotation (see below).
  • Handedness is (also) stored in your projection matrix.
  • A easy way to test if your matrices are using left or right handedness, is by rotating your object around the Y with a positive angle, see below how the rotation should look like. You'll see how many libraries out there are doing this wrong.. I was seriously surprised. Tested 5 libraries and they all got it wrong (mixing LH with RH).

Left and Right Handedness

left_right_hand

Rotations

The arrows point into the direction of positive rotations.

Rotations

The video below shows a positive rotation around the Y-axis for a right handed coordinate system:

positive_rotation_around_y_in_right_handed_system

This video shows a positive rotation around the X-axis for a right handed coordinate system:

positive_rotation_around_x_in_right_handed_system

This video below shows a positivie rotation around the X-asix for a left handed coordinate system:

positive_rotation_around_x_in_left_handed_system

Blender Bones

This is a must read that describes the blender bone model in detail.

Quaternions

Okay, so after some reading, chats, experimenting I found out that bones/armatures in Blender use a different space then the models/meshes/vertices that you create. Bones use Y-up, meshes Z-up. Though they both use a RH-system. The IQM exporter contains quaternions that represent the rotation of the bones. Quaternions are great for describing rotations but you need to be aware that when you use quaternions to represent rotations, the quaternions are unit-quaternions (e.g. their length is 1). I didn't use quaternions before, so here is a braindump:

  • When using quaternions to represent rotations, you use unit-quaternions
  • You can multiply quaternions. When you multiply two unit quaternions, the result is still a unit quaternions (and therefore can still be used to represent a rotation).
  • You read quaternion multiplications, when they represent rotations, from right-to-left. So not like proj * view * model but model * view * proj.

Stepping a bit back to the quaternion you get from the default bone in Blender, (0.707, 0.0, 0.0, 0707) (xyzw). After some reading I figured out that this is a +90 rotation around X. Finally this made sense, because the bone uses Y-up (that is the direction from tail to head points in the Y-axis direction). To align it with the Z-axis of Blenders object space, it needs to rotate 90 degrees around X. So there you have it :-). While starting with this skeleton animation, this was the first part that I had to figure out and it took me way too long then I wanted to get a firm understanding about this.

So, next step is to draw all the bones I read from IQM. From kaito on irc (#blendercoders), I got this link to a page that describes blenders bone system in detail

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment