2
$\begingroup$

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:

enter image description here

If I remove the skins from the model I get this:

enter image description here

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?

$\endgroup$
6
  • $\begingroup$ Node transforms are hierarchical, so would it work to just apply the transform to the root node(s) of the file (or create a new root node to hold your transform, and make it the parent of all the file's root nodes)? Or are you trying to actually remove all transforms by baking them onto all the bottom-level vertex and animation data? $\endgroup$ Commented Nov 12, 2022 at 20:04
  • $\begingroup$ @NathanReed I am trying to mutate 100% of all the data. So in the original data, y is up. I am trying to change it so that z is up. Maybe I am wrong but that sounds like every single datum that uses coordinates must have it's data altered. Transform is a matrix because I want to later use this same logic to also translate/rotate the model data to change the origin. $\endgroup$
    – Makogan
    Commented Nov 13, 2022 at 6:29
  • 1
    $\begingroup$ OK, that definitely sounds like something where you just want to alter the root transform and let it automatically affect everything under it through the transform hierarchy. $\endgroup$ Commented Nov 14, 2022 at 15:03
  • $\begingroup$ @NathanReed It will be wrong, I need to modify the mesh as well, so the mesh will have been modified such that all its x,y coords are flipped, so the nodes are wrong unless tehya re modified to. $\endgroup$
    – Makogan
    Commented Nov 15, 2022 at 8:44
  • $\begingroup$ What I'm saying is you can flip the coordinates with a matrix on the top level node. You don't need to modify the individual mesh vertices at all. It's just a rotation. $\endgroup$ Commented Nov 15, 2022 at 14:56

2 Answers 2

1
$\begingroup$

When transforming normal vectors we have to be careful to check that the transform itself is equal to its own inverse transpose. Or just do an inverse transpose on the matrix. This is usually the case, but checking it makes the requirement explicit rather then implied. (a scale in the transform for example would result in incorrect normal vectors)

When transforming a matrix from one coordinate system to another where we have a matrix M that transforms vectors from coordinate system A to coordinate system B then the transform from A to B is $B=MAM^{-1}$

$\endgroup$
0
$\begingroup$

I had the same question as you, and finally figured out a simple answer.

Add a new node to your glTF file. Make this node the parent of both the mesh node and the skeleton (root bone node). Then you can simply apply any transformations to this new root node, and they will affect the mesh, skeleton, and all animations, without having to do any matrix or vector math:

"scene": 0, 
  "scenes": [
    {
      "nodes": [0]
    }
  ],
  "nodes": [
    {
      "name": "root node",
      "children": [1, 2],
      *** Add your translation, rotation, and/or scale here ***
    },
    {
      "mesh": 0,
      "skin": 0
    },
    {
      "name": "bone0"
      "children": [3],
      "translation": [0, 0, 0],
      "rotation": [0, 0, 0, 1],
      "scale": [1, 1, 1]
    }
    {
      "name": "bone1"
      "children": [...],
      "translation": [0, 0, 0],
      "rotation": [0, 0, 0, 1],
      "scale": [1, 1, 1]
    },
    ...
  ], ...
$\endgroup$
1
  • $\begingroup$ This does not address the issue as this is not rotating the data. It is modifying the hierarchy so that a transformation is applied during rendering. Those are not the same thing. $\endgroup$
    – Makogan
    Commented Jun 15 at 23:18

Not the answer you're looking for? Browse other questions tagged or ask your own question.