原文地址:http://ogldev.atspace.co.uk/www/tutorial38/tutorial38.html
background
finally, it is here. the tutorial that millions of my readers( i may be exaggerating here, but definitely a few) have been asking for. skeletal animation, also known as skinning, using the assimp library.
skeletal animation is actually a two part process.
the first one is executed by the artist and the second by u, the programmer (or rather, the engine that u wrote).
the first part takes place inside the modeling software and is called Rigging. 绑定骨骼
what happens here is that the artist defines a skeleton of bones underneath the mesh.
the mesh represents the skin of the object (be it a human, monster or whatever) and the bones are used to move the mesh in a way that would mimic actual movement in the real world.
this is done by assigning each vertex to one or more bones.
when a vertex is assigned to a bone a weight is defined that determines the amount of influence that bone has on the vertex when it moves.
the common practice 通常 is to make the sum of all weights 1 (per vertex). for example, if a vertex is located exactly between two bones we would probably want to assign each bone a weight of 0.5 because we expect the bones to be equal in their influence on the vertex.
however, if a vertex is entirely within the influence of a single bone then the weight would be 1 (which means that bone autonomously 自治 controls the movement of the vertex).
here is an example of a bone structure created in blender:
what we see above is actually an important part of the animation.
the artist riggs together the bone structure and defines a set of key frames for each animation type (“walk”, “run”, “die”, etc).
the key frames contain the transformations of all bones in critical 重要的 points along the animation path.
the graphics engine interpolates between the transfomations of the keyframes and creates a smooth motion between them.
the bone structure used for skeletal animation is often heirarchical. this means that the bones have a child/parent relationships so a tree of bones is created.
every bone has one parent except for the root bone. in the case of the human body, for example, u may assign the back bone as the root with child bones such as arms and legs and finger bones on the next level done.
when a parent bone moves it also moves all of its children, but when a child bone moves it does not move it parent (our fingers can move without moving the hand, but when the hand moves it moves all of its fingers). from a practical point of view this means that when we process the transformations of a bone we need to combine it with the transformations of all the parent bones that lead from it to the root.
we are not going to discuss rigging any further. it is a complex subject and outside the domain of graphics programmers.
modeling software has advanced tools to help the artists do this job and u need to be a good artist to create a good looking mesh and skeleton. let us see what the graphics engine needs to do in order to make skeletal animation.
the first stage is to augument 不知道啥意思 the vertex buffer with per vertex bone information.
there are several options available but what we are going to do is pretty straightforward.
for each vertex we are going to add an array of slots where each slot contains a bone ID and a weight.
to make our life simpler we will use an array with four slots which means no vertex can be influenced by more than four bones.
if u are going to load models with more bones u will need to adjust the array size but for the Doom 3 一个游戏 model that is part of this tutorial demo four bones are enough.
so our new vertex structure is going to look like this:
the bone IDs are indices into an array of bone transformations. these transfomations will be applied on the position and normal before the WVP matrix. (i.e. they transform the vertex from a “bone space” into local space). the weight will be used to combine the transformations of several bones into a single transformation and in any case the total weight must be exactly 1 (responsibility of the modeling software). usually, we would interpolate between animation key frames and update the array of bone transformations in every frame.
the way the array of bone transformations is created is usually the tricky part.
the transformations are set in a heirarchical structure (i.e. tree) and a common practice is to have a scaling vector, a rotation quaternion and a translation vector in every node in the tree.
in fact, each node contains an array of these items.
every entry in the array must have a time stamp.
the case where the application time will exactly match one of the time stamps is probably rare
so our code must be able to interpolate the scaling/rotation/translation to get the correct transformation for the point in time of the application.
we do the same proces for each node from the current bone to the root and multiply this chain of transformations together to get the final result. we do that for each bone and then update the shader.
everything that we talked about so far has been pretty generic.
but this is a tutorial about skeletal animation with assimp, so we need to dive into that library again and see how to do skinning with it. the good thing about Assimp is that it supports loading bone information from several formats. the bad thing is that u still need to do quite a bit of work on the data structures that it creats to generate the bone transfomations that u need for the shaders.
let us start at the bone information at the vertex level. here is the relevant pieces in assimpl data structrues:
as u probably recall from the tutorial on assimp, everything is contained in the aiScene class (an object of which we get when we import the mesh file).
the aiScene contains an array of aiMesh objects. an aiMesh is a part of the model and contains stuff at the vetex level such as position, normal, texture coordinates, etc.
now we see that aiMesh also contains an array of aiBone objects.
unsuprisingly, an aiBone represents one bone in the skeleton of the mesh.
each bone has a name by which it can be found in the bone heirarchy (see below),
an array of vertex weights and a 4x4 offset matrix.
the reason why we need this matrix is because the vertices are stored in the usual local space.
this means that even without skeletal animation support our existing code base can load the model and render it correctly.
but the bone transformations in the heirarchy work in a bone space (and every bone has its own space which is why we need to multiply the transformation together). so the job of the offset matrix is to move the vertex position from the local space of the mesh into the bone space of that particular bone.