An .x file animates its frames. Each animation names one frame and gives keys for its rotation, scale and position, or for its whole matrix, over time. A skinned mesh then follows those frames as bones, through per-vertex weights. All the templates here are from Microsoft’s DirectX 9 list.
Animation sets and animations
template AnimationSet {
<3D82AB50-62DA-11cf-AB39-0020AF71E433>
[ Animation <3D82AB4F-62DA-11cf-AB39-0020AF71E433> ]
}
template Animation {
<3D82AB4F-62DA-11cf-AB39-0020AF71E433>
[...]
}
An AnimationSet holds one or more Animation objects that
share one clock: advancing the set’s time advances all of them. A file may hold
several sets, such as a walk and a run. Each Animation should hold one
reference to the frame it moves, written like { Bone01 }, at least one
AnimationKey, and optionally an AnimationOptions.
AnimationKey and its keys
template AnimationKey {
<10DD46A8-775B-11CF-8F52-0040333594A3>
DWORD keyType;
DWORD nKeys;
array TimedFloatKeys keys[nKeys];
}
template TimedFloatKeys {
<F406B180-7B3B-11cf-8F52-0040333594A3>
DWORD time;
FloatKeys tfkeys;
}
template FloatKeys {
<10DD46A9-775B-11cf-8F52-0040333594A3>
DWORD nValues;
array float values[nValues];
}
| keyType | Keys hold | Values per key | Order |
|---|---|---|---|
| 0 | Rotation | 4 | A quaternion; readers such as Assimp take the values as w, x, y, z |
| 1 | Scale | 3 | x, y, z |
| 2 | Position | 3 | x, y, z |
| 3 | Matrix | 16 | A whole transform, as in Matrix4x4 |
| 4 | Matrix | 16 | Not in Microsoft’s list, but written by some exporters and read as a matrix by Assimp |
time is in animation ticks; see AnimTicksPerSecond below. An
animation usually has one key set for each of rotation, scale and position, or one
matrix key set. Microsoft does not state the order of the quaternion values.
Animation {
{ Arm }
AnimationKey {
2; // position keys
2; // two keys
0;3;0.0,0.0,0.0;;, // at tick 0
4800;3;0.0,1.0,0.0;;; // at tick 4800
}
}
Arm up by one unit.AnimationOptions
template AnimationOptions {
<E2BF56C0-840F-11cf-8F52-0040333594A3>
DWORD openclosed;
DWORD positionquality;
}
| Member | Value | Meaning |
|---|---|---|
openclosed | 0 | Closed animation, the default when there is no AnimationOptions |
| 1 | Open animation | |
positionquality | 0 | Position keys are joined by a spline |
| 1 | Position keys are joined linearly |
Microsoft does not define open and closed any further.
AnimTicksPerSecond
template AnimTicksPerSecond {
<9E415A43-7BA6-4a73-8743-B73D47E88476>
DWORD AnimTicksPerSecond;
}
An object, usually at the top level of the file, giving the number of ticks per second for the key times of the file’s animations. Microsoft’s description says only that it converts animation time stamps to global time and mentions frame rates of 30, 60, 24 and 25.
CompressedAnimationSet
template CompressedAnimationSet {
<7F9B00B3-F125-4890-876E-1C42BF697C4D>
DWORD CompressedBlockSize;
FLOAT TicksPerSec;
DWORD PlaybackType;
DWORD BufferLength;
array DWORD CompressedData[BufferLength];
}
| Member | Meaning |
|---|---|
CompressedBlockSize | Size in bytes of the compressed key frame data |
TicksPerSec | Key frame ticks per second |
PlaybackType | 0 D3DXPLAY_LOOP, repeat endlessly; 1 D3DXPLAY_ONCE, play once and stop on the last frame; 2 D3DXPLAY_PINGPONG, play forwards and backwards endlessly |
BufferLength | Length of the data in DWORDs: (CompressedBlockSize + 3) / 4. Microsoft’s page calls it a size in bytes, but the formula and the array give DWORDs |
CompressedData | The compressed key frames |
The compressed data is produced and read by D3DX’s keyframed animation compression, whose format Microsoft has not published.
Skinning
template XSkinMeshHeader {
<3CF169CE-FF7C-44ab-93C0-F78F62D172E2>
WORD nMaxSkinWeightsPerVertex;
WORD nMaxSkinWeightsPerFace;
WORD nBones;
}
template SkinWeights {
<6F0D123B-BAD2-4167-A0D0-80224F25FABB>
STRING transformNodeName;
DWORD nWeights;
array DWORD vertexIndices[nWeights];
array float weights[nWeights];
Matrix4x4 matrixOffset;
}
Mesh.A skinned mesh holds one XSkinMeshHeader and then one
SkinWeights object for each bone that moves it.
| Member | Meaning |
|---|---|
nMaxSkinWeightsPerVertex | Most bones that affect any one vertex |
nMaxSkinWeightsPerFace | Most distinct bones that affect the three vertices of any one face |
nBones | Number of bones that affect the mesh, and so the number of SkinWeights objects |
transformNodeName | The name of the bone: a Frame elsewhere in the file |
nWeights | How many vertices this bone affects |
vertexIndices | The vertex numbers it affects |
weights | The weight for each of those vertices, in the same order |
matrixOffset | Transforms the mesh’s vertices into the bone’s space; combined with the bone’s current transform it gives the vertices’ world positions as moved by this bone |
In the binary encoding the three WORD members of XSkinMeshHeader are each
stored as a four-byte integer, as all integers in a binary list are.