Skeletal animation

I need animated 3D models, and skeletal animation is pretty much standard everywhere. I was surprised by the lack of information on the internet about it or maybe I’m just looking in the wrong places.

I understand the theory; each vertex is given a number of bones that affect it, and the vertex is transformed in a vertex shader. In practice I have no idea how to do this, again because I haven’t studied university math yet. As far as I’ve managed to uncover each bone is a 4x4 transformation matrix. Bones also have a hierarchy (fingers attached to hand, hand attached to elbow, elbow attached to shoulder, e.t.c). In the 3D model format I want to implement a loader for bones are stored as a 3D rotation vector + an angle and a 3D translation vector.

My real question is: How do I generate these matrices? Create an identity matrix, rotate it and translate it? The other way around? What about the hierarchy? How/when do I multiply it with its parent matrix? WHAT IS GOING ON?! :’(

When I have my bone matrices loaded and ready I just send them as instance specific attributes to GLSL and access them in a vertex shader. So I multiply it by the model matrix first, then I transform this vertex with the bone matrices and average the result? Ah, matrices… I’ve hated you since the second movie!!!

I do realize that this is indeed over my head, but I just want to get it working more than actually understanding everything completely…

Has I understand skeletal animation :

  • To each bone, a matrix is associted. This matrix is composed of a translation (position of the root of this bone in the parent local location) and a rotation (from a quaternion to interpolate). Ali = Ati * Ari
  • To each vertices, several matrices can be associated with a ratio ( rji, the most basic skeletal animation is done with a vertex associeted with only one matrix with a ratio of 1). Most vertices with have a ratio on 1 for one matrix and 0 for the other but vertices near joins.
  • The position of the vertice is the position when all rotation are in the initial position.

So before calling the shader, you have to compute all the matrix by composing the child matrix with the parent matrix. For exemple Al1 is the local matrix for the body, Al2 local matrix for the pelvis, Al3 the left upper leg, Al4 the the left lower leg. Then the global matrix for the lower leg is :
Ag4 = Ap1 * Ap2 * Ap3 * Al4

At initialisation you have to compute, the inverse of the matrices on each bones at the initial position :
Ag4’-1 = (Ap’1 * Ap’2 * Ap’3 * Al’4)-1

So for the local position of the vertex before rotation is : Agi’-1 * Pj
Then you get the global position of the vertex after rotation : Agi * Agi’-1 * Pj

Then in the shader for the vertex j :
Pgj = sum(i=0 to n , rij * Agi * Agi-1 * Pj) / sum (i=0 to n, rij)

In pratice :

  • Agi * Agi-1 is compute before the shader
  • the ration are done to have sum (i=0 to n, rij) = 1
  • you limite the number of matrices associeted to a vertex (i don’t think that more than 4 matrices is that usefull).

Ardor3D supports skeletal animations but I assume you would like to implement this feature by yourself.

@Bonbon-Chan thank you for your nice explanation.

You may find this topic useful. It’s old (2005) and a bit specific to a particular file format, but most skeletal animated data are described in about the same way.

Edit: You can find sample shader code here (4.4 Skinning)

@Bonbon-Chan
Thanks a lot for your explanation! I think I understand more of the basics now!

I only have one real question right now: How do I generate a bone matrix from a translation vector and a rotation quaternion? I want to try to do this in software first since that’s less error prone, and I’ll skip interpolation for now. I’ll implement all that later when I get a better grasp of the math going on here.

Thanks again for your response! I’ll have to read it a few more times…

That’s one hell of a verbose thread! I’ll look through it a bit, but like I said, It think I understand the concept of how this works, but not the math behind it. I’ll probably be back with more questions if I can’t figure it out after reading everything here…

[quote=“theagentd,post:5,topic:37926”]
For a row-major matrix:

public Matrix4f set4f(Vector3f p, Quat r) {
	float r2x = 2.0f * r.x;
	float r2y = 2.0f * r.y;
	float r2z = 2.0f * r.z;

	this.m00 = 1.0f - (r2y * r.y + r2z * r.z);
	this.m10 = r2x * r.y - r2z * r.theta;
	this.m20 = r2x * r.z + r2y * r.theta;
	this.m30 = p.x;

	this.m01 = r2x * r.y + r2z * r.theta;
	this.m11 = 1.0f - (r2x * r.x + r2z * r.z);
	this.m21 = r2y * r.z - r2x * r.theta;
	this.m31 = p.y;

	this.m02 = r2x * r.z - r2y * r.theta;
	this.m12 = r2y * r.z + r2x * r.theta;
	this.m22 = 1.0f - (r2x * r.x + r2y * r.y);
	this.m32 = p.z;

	this.m03 = 0.0f;
	this.m13 = 0.0f;
	this.m23 = 0.0f;
	this.m33 = 1.0f;

	return this;
}

That’s awfully convenient! =D

EDIT: What the hell does “bind pose” mean?!