I am trying to transform the mesh data in a gltf file and then modify the skin and animation data accordingly.
Let's say we want to transform the data using a 4x4 homogeneous matrix. For simplification let us say the transformation is just swapping the y and z axes.
Doing it to the mesh data is simple enough:
Something like this:
for mesh in &gltf.meshes
{
for primitive in &mesh.primitives
{
for position in gltf
.data_from_accessor::<Vec3>(primitive.attributes.position)
.unwrap()
{
*position = transform_vec3(&position, &transform, true);
}
for normal in gltf
.data_from_accessor::<Vec3>(primitive.attributes.normal)
.unwrap()
{
*normal = transform_vec3(&normal, &transform, false);
}
}
}
Now the issue is, after doing this, what must we do to the skin data and animation data to correctly change it so that now the y and z axes are swapped.
We know that before our transformation, the animations are effectively computed as:
$$(\sum \lambda_i A_i \cdot M_i) \cdot v$$
where $\lambda_i, A_i, M_i$ are the weights, animation matrices and inverse bind matrices.
Now, after modifying the vertices of the mesh data we have:
$$(\sum \lambda_i A_i \cdot M_i) \cdot T v$$
So we need to modify our matrices such that the transformation $T$ is applied only once after all other transformations are applied, so:
$$T(\sum \lambda_i A_i \cdot M_i)T^{-1} T v$$ $$(\sum \lambda_i TA_i \cdot M_iT^{-1}) T v$$
The above formula suggests that the correct approach is to apply the transformation to all animation data and its inverse to the ibms.
Something like:
- for each ibm matrix ibm -> ibm * $T^{-1}$
- for each node in the skin node -> $T$ * node
- for each animation output in the skin, output -> $T$ * output
This fails miserably in all real life data I try and I don't understand why. For example this is the result on a model:
If I remove the skins from the model I get this:
Which is the expected output, the mesh data has flipped the z and the y.
So what must be done to convert the animation data to match the transform to the mesh?