For vertex skinning you basically need to export the following data:
Per vertex:
A list of bone indices (typically 4).
A list of weights - the weights MUST sum to 1.
Per bone:
The inverse of the bind pose transform - this is because the skin's vertices are stored in the bind pose - ie. if you just draw the skin without doing any skinning you'll see the figure standing as they were when you applied the skin to the model in the modelling package - typically artists will use a "star" position to minimse problems with the armpits and crotch. You need this matrix so that you can "get back to the bind pose" before applying a delta rotation (and possibly translation) to distort the model. Or, in other words you want to subtract off the rotation and translation caused by the bind pose from the animation (but in matrix math this is done by multiplying by the inverse). This is all done with a single matrix in the shader, but you need this information separately to correctly set up the matrices before passing them to the shader.
Then, at runtime, on the CPU you do the following:
Interpolate the animation (using quaternions or however you want to do it). You will probably be using local transforms for the animation so then you'll need to multiply each bone by its parent's matrix to give the full transform.
Next you need to calculate: inverse_bind_pose[bone]*bone_matrix[bone] for each bone to give the final transform that will be used for skinning, and upload these matrices to the GPU in vertex constants.
In the shader you simply calculate:
Code: Select all
final_pos=(0,0,0)
for each influence
final_pos+=(pos*bone_matrix[bone_index[influence]]*bone_weight[influence])
Alternatively, if you have multiple attributes that you need to skin (eg. position, normal, tangent, binormal for normal mapping) you can weight the matrices instead of the positions:
Code: Select all
final_matrix=0
for each influence
final_matrix+=bone_matrix[bone_index[influence]]*bone_weight[influence]
then transform each of the attributes by final_matrix. This gives the same result as the pseudocode above but is typically much more efficient (only num_attributes matrix multiples + a bunch of multiplies and adds vs num_attributes*num_influences matrix multiplies). It will obviously be about the same, or slightly slower if you are only skinning positions though
Note that normally you want to upload 3x4 bone matrices to the shader (transposed so that they fit into 3 vertex constants each) - since the transforms will always be affine.