Skeletal Models
This is another one of those subjects where I'm not sure what the right words are to use, so please forgive my lack of accepted convention.
Skeletal Models refers to a figure composed of multiple rigid 3D models rendered together to assemble a figure with joints.
This page will discuss some ways of handling this problem, and make you aware of some more advanced topics that game programmers must face when rendering these figures.
You should be familiar with Rendering 3D Worlds so that you understand the concept of forward transformations and the orientation structure I use.
Here's a simple example... Imagine two rods connected at the end that can pivot on that joint. How do we go about rendering this? Well, there's a few problems to solve here:
We can use a single model of an elongated cube for each of the pieces.
Two COrient3D structures will work for the overall orientation and the joint.
To render this, perform the following tasks, after setting the OpenGL frustrum as in Rendering 3D Worlds:
That's all it takes. You can set the overall object orientation to anything you like. The joint orientation can also be whatever you like, except that the position(p) of the joint MUST be such that it lies at the end of the first piece, and that the rendering of the second piece must start with one end lying directly upon the joint. For example, if the pieces have a length of 2.0 along the z axis in 3D space, then the position of the joint must be (0.0f, 0.0f, 2.0f). One end of the second piece must lie on (0.0f, 0.0f, 0.0f). Get it?
The joint orientation is in relation to the overall object orientation. since we perform a second transformation on top of the object transformation, the object transformation ultimately determines the way that the joint transformation affects the second piece. This happens because we DID NOT POP the matrix after rendering the first piece.
How can we expand this methodology to render more complicated objects?
What it takes is storing the skeleton structure in a tree. The tree itself contains references to models and has positions for the models in relation to the joint orientations. All the is left is to have each joint refer to a joint rotation stored at the object level. The root of the tree represents the position at the primary object orientation. Each parse down the tree represents performing the next forward transformation and pushing the matrix, recursing up the tree pops the last matrix.
Note that since you could have many objects with the same skeletal structure in your game, it is imporant to store the joint orientations separately from the tree. That way the tree can be reused for every object that uses it, and only the joint orientations themselves need to be stored at the object level.
The next challenge: How do we use this to perform realistic looking animations? Well, there are a few ways that I know of...
How do we iterate between keyframes? Assume for the moment that the only difference between keyframes is the joint orientations. For one orientation to tend itself to the other, three thigns must happen: The positions must match, the f vector must match and the u vectors must match (the l vector automatically matches at that point). One joint orientation tends to match another joint orientation by doing the following things:
So, figure out how much p you must move per MS, get a rotation vector for f and calculate the angle per MS to rotate along that vector, and get the angle that u must rotate along f's current position to match. Apply all these rotations based on MS and you will have a single joint iteration. Repeat for all joints.
For a more simplified way of tending one orientation to another, especially for keyframes that are very close together, it may be good enough to just move one orientation's p to the other. Or move p and perform the f rotation without the u rotation. It depends on what looks good and keeps the program running smoothly.
Pure skeleton animations are wonderful for robotic figures and can make use of the above methods.
More complex models may require more work than this. For instance, these joint orientations may only be for the skeleton beneath the model. The actual skin of the model is what is rendered, and it is possible to determine the position of the skin vertices based entirely upon the position of the skeleton. Such animation may be best implemented using the second iteration option above, because the extra calculations involved are immense.
On the subject of complex animations, it is possible for more than one animation set to be running on a single object at one time. Imagine a walker robot walking along with an antenna dish on its topside constantly rotating. Also, some joints are reserved for program-control. For instance, a character could be running along, but the head is pitching at an angle equal to where the player is looking. It will naturally be up to you, the programmer, to make sure that groups of active animations and program controlled joints do not interfere with each other. Some situations may require a little ingenuity. For instance, two joints, one a child of the other, on a single location can take advantage of both animation controlled and program controlled adjustments for the child objects of that joint.
A single key frame is simply a group of joints set to a pre-defined state. Animation loops involve several key frames, usually involving the same group of joints throughout.
Some animations aren't performed by keyframe loops at all. A truly realistic simulation of a dinosaur walking along terrain, adjusting its legs and posture based on its speed, direction and the slope of the terrain is a great example. There are a lot of calculations for this, and I haven't even touched this idea, but I'm sure the effect is very worth it. Even the wizards of Jurassic Park, I'm sure, resorted to pre-defined animation sequences instead of purely dynamic calculations that occur by just telling the dinosaur where they want it to go. One of the difficulties in this method is to start at the feet and trace up through the body until the position of the overall object can be calculated. The feet and other appednages can't be too far away from each other, so strides have to be carefully controlled as well. I won't even go there!