Java – from Import 3D skeleton animation from SMD model
I'm writing one SMD importer, I'm trapped in the bone animation part The problem is that I don't know exactly how it works I'm using this to write the exporter, but it doesn't show how to use the information stored in the file
I think all vertices with the same bone ID should be grouped, translated and rotated, because you can't rotate each vertex But I don't know if I'm right. Even if I am, I still don't know how to do this through script
So the question is: how do I use the skeleton animation information stored in the file?
Solution
I'm not particularly familiar with the SMD format, but here
Note: this answer assumes that you know how to construct composite transforms for objects / nodes This is a matrix that combines its translation, rotation and scaling (although it seems that scale is not used in SMD) In addition, matrix multiplication, matrix inversion and matrix * vector multiplication are used
Bones and animation
The nodes of the model form a tree; Except for the root bone (node part), every bone has a parent bone Each node has its own local transformation (position and rotation)
Local node Transformation: the local transformation of a node is constructed from its position and rotation 4 × 4 matrix, which transforms the point from its local space to the space of its parent node: if the vector representing the position in the node space is multiplied by the matrix to obtain the vector in the parent space For details on how to do this, see this link Google a bit more
In SMD, bone transformations are defined only in keyframes (skeleton parts) in animation The "reference" SMD file has a single frame animation; The position and rotation of each bone node in the model reference position
The animation SMD file has an animation sequence containing multiple frames, each frame specifying a different transformation of (some) bones When playing an animation, you can interpolate between frames according to the time of the frame and the current scene / game time, and transform (rotate the position) for each bone
Get static bone transformation
In preprocessing (when the mesh is loaded), you need to calculate the so-called "rest" bone transformation These are the model to bone space transformations for each bone at the reference position The reasons are as follows:
All vertex positions are defined in model space, but ultimately, vertex transformations must start in bone space because you want vertices to move with a single bone Therefore, you must first convert the vertex position into bone space This is the source of static bone turnover
Therefore, the static transformation we are looking for converts vertices from model space to bone space Place all bones in reference positions Traverse the tree from the root node and connect the transformation matrix So, for example, for an upper arm node, you get the transform:
transform = root * spine * shoulderR * upperArmR
However, this is a transformation from upper arm space to model space Therefore, the static bone transformation can be obtained by reversing the matrix Do this for each bone and store these matrices
Note that the rest transformation does not change over time; They are repaired according to the reference position of the model
Vertex / bone Association
Each vertex is associated with one or more bone nodes For each such association, vertices have corresponding weights Typically, the sum of all weights is 1 In SMD, these associations are defined in triangular segments According to the page you linked, the format is:
triangles my_material bone_id x y z nx ny nz u v bone_links
This defines a vertex at (x, y, z) and eventually connects it to the bone_ ID (assuming a weight of 1) bone_ The links section can (sort) override it and specify multiple associations, as follows:
bone_links = num_links bone_id[0] weight[0] bone_id[1] weight[1] ... etc.
If the weight is not equal to 1, the remaining weight is converted to the original bone_ ID Association
Therefore, the example vertices associated with bones 0, 1, and 2 will be:
0 x y z nx ny nz u v 3 0 0.15 1 0.35 2 0.5
Vertex Transformation
This is where we finally determine the vertex position according to the current bone transformation As mentioned earlier; Based on the current time and animation, you can determine (insert) the current bone transformation For each bone, the transformation of the bone to the world is calculated Example (we've seen it before):
boneToWorld = root * spine * shoulderR * upperArmR
Now, for vertices associated with a single bone, its animation / skin position is given below:
vertexPosAnimated = boneToWorld * boneAtRest * vertexPosModel
This first converts the vertex position from model space (vertexposmodel) to its associated bone space (this transformation does not change over time) Then, using the current position of the bone, the vertices are converted from bone to model space again This allows it to move with the bone as the transformation changes
It is observed that when the bone is currently in the rest position, boneatrest is the inversion of bonetoworld, so bonetoworld * boneatrest is the identity matrix, so the vertex position remains unchanged, which is correct!
Finally, since vertices can be associated with multiple bones instead of the above, we calculate the above weighted sum of each related bone For example, for vertices associated with 3 bones:
vertexPosAnimated = boneToWorld[0] * boneAtRest[0] * vertexPosModel * weight[0] + boneToWorld[1] * boneAtRest[1] * vertexPosModel * weight[1] + boneToWorld[2] * boneAtRest[2] * vertexPosModel * weight[2];
Last thought
These are some broad strokes. I didn't even discuss shader implementation (if that's what you want to do), but I think I've covered all the principles, and it's a long answer
One thing I found helpful in 3D engine development was M3G documentation (old Java mobile 3D API) The entries on SkinnedMesh basically describe what I post here
In addition, try to understand the concept of converting vertices from model to bone space using static bone transformation, and return again using its current transformation This is the key to the whole thing
Good luck!