Skip to main content
Notice removed Draw attention by CommunityBot
Bounty Ended with no winning answer by CommunityBot
Notice added Draw attention by Makogan
Bounty Started worth 50 reputation by Makogan
added 589 characters in body
Source Link
Makogan
  • 1.7k
  • 13
  • 29

One thing that is mathematically sound isI am trying to grabtransform the mesh data in a gltf modelfile and apply some arbitrary linear transformation to it, like a rotation or a translationthen modify the skin and animation data accordingly.

Let's say we want to transform the transformation is encoded asdata using a 4x4 homogeneous matrix.

I think it needs to be applied to For simplification let us say the meshes, nodes, ibms intransformation is just swapping the skins,y and animationsz axes.

Starting simple, I want to applyDoing it to only the meshes.mesh data is simple enough:

i.e. somethingSomething like this:

        for mesh in &self&gltf.meshes
        {
            for primitive in &mesh.primitives
            {
                for position in selfgltf
                    .data_from_accessor::<Vec3>(primitive.attributes.position)
                    .unwrap()
                {
                    *position = transform_vec3(&position, &transform, true);
                }

                for normal in selfgltf
                    .data_from_accessor::<Vec3>(primitive.attributes.normal)
                    .unwrap()
                {
                    *normal = transform_vec3(&normal, &transform, false);
                }
            }
        }

ThisNow the issue is ok, after doing this, what must we do to the skin data and yieldsanimation 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$$ enter image description here$$(\sum \lambda_i TA_i \cdot M_iT^{-1}) T v$$

Ok now I wantThe above formula suggests that the correct approach is to apply the transformation to all animation data and its inverse to the nodes, so I attempt thisibms.

Something like:

        for node in &mut self.nodes
        {
            let mut mat : Mat4 = compose_homogeneous(&node.scale, &node.rotation, &node.translation);
            mat = transform * mat;

            let (new_scale, new_rot, new_trans) = decompose_homogeneous(&mat);

            node.rotation = new_rot;
            node.translation = new_trans;
            node.scale = new_scale;
        }
  • 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

Now gltf viewers showThis 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

Why?enter image description here

If I have tested things and both compose_homogeneous and decompose_homogeneous are correct. Why amremove the skins from the model I gettingget this degenerate:

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?

One thing that is mathematically sound is to grab a gltf model and apply some arbitrary linear transformation to it, like a rotation or a translation.

Let's say the transformation is encoded as a 4x4 homogeneous matrix.

I think it needs to be applied to the meshes, nodes, ibms in the skins, and animations.

Starting simple, I want to apply it to only the meshes.

i.e. something like this:

        for mesh in &self.meshes
        {
            for primitive in &mesh.primitives
            {
                for position in self
                    .data_from_accessor::<Vec3>(primitive.attributes.position)
                    .unwrap()
                {
                    *position = transform_vec3(&position, &transform, true);
                }

                for normal in self
                    .data_from_accessor::<Vec3>(primitive.attributes.normal)
                    .unwrap()
                {
                    *normal = transform_vec3(&normal, &transform, false);
                }
            }
        }

This is ok and yields: enter image description here

Ok now I want to apply to the nodes, so I attempt this:

        for node in &mut self.nodes
        {
            let mut mat : Mat4 = compose_homogeneous(&node.scale, &node.rotation, &node.translation);
            mat = transform * mat;

            let (new_scale, new_rot, new_trans) = decompose_homogeneous(&mat);

            node.rotation = new_rot;
            node.translation = new_trans;
            node.scale = new_scale;
        }

Now gltf viewers show this: enter image description here

Why?

I have tested things and both compose_homogeneous and decompose_homogeneous are correct. Why am I getting this degenerate output?

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?

Rollback to Revision 1 - Edit approval overridden by post owner or moderator
Source Link
Makogan
  • 1.7k
  • 13
  • 29
        for mesh in & self&self.meshes
        {
            for primitive in & mesh&mesh.primitives
            {
                for position in self
                    .data_from_accessor:: <Vec3>(primitive.attributes.position)
                    .unwrap()
                {
            * position       *position = transform_vec3(&position, &transform, true);
                }

                for normal in self
                    .data_from_accessor::<Vec3>(primitive.attributes.normal)
                    .unwrap()
                {
      {
            * normal *normal = transform_vec3(&normal, &transform, false);
                }
            }
        }
for node in &mut self.nodes
{
    let mut mat : Mat4 = compose_homogeneous(&node.scale, &node.rotation, &node.translation);
    mat = transform * mat;

    let (new_scale, new_rot, new_trans) = decompose_homogeneous(&mat);

    node.rotation = new_rot;
    node.translation = new_trans;
    node.scale = new_scale;
}
        for node in &mut self.nodes
        {
            let mut mat : Mat4 = compose_homogeneous(&node.scale, &node.rotation, &node.translation);
            mat = transform * mat;

            let (new_scale, new_rot, new_trans) = decompose_homogeneous(&mat);

            node.rotation = new_rot;
            node.translation = new_trans;
            node.scale = new_scale;
        }
for mesh in & self.meshes
{
    for primitive in & mesh.primitives
    {
        for position in self
            .data_from_accessor:: <Vec3>(primitive.attributes.position)
                .unwrap()
                {
            * position = transform_vec3(&position, &transform, true);
        }

                for normal in self
                .data_from_accessor::<Vec3>(primitive.attributes.normal)
                    .unwrap()
                    {
            * normal = transform_vec3(&normal, &transform, false);
        }
    }
}
for node in &mut self.nodes
{
    let mut mat : Mat4 = compose_homogeneous(&node.scale, &node.rotation, &node.translation);
    mat = transform * mat;

    let (new_scale, new_rot, new_trans) = decompose_homogeneous(&mat);

    node.rotation = new_rot;
    node.translation = new_trans;
    node.scale = new_scale;
}
        for mesh in &self.meshes
        {
            for primitive in &mesh.primitives
            {
                for position in self
                    .data_from_accessor::<Vec3>(primitive.attributes.position)
                    .unwrap()
                {
                    *position = transform_vec3(&position, &transform, true);
                }

                for normal in self
                    .data_from_accessor::<Vec3>(primitive.attributes.normal)
                    .unwrap()
                {
                    *normal = transform_vec3(&normal, &transform, false);
                }
            }
        }
        for node in &mut self.nodes
        {
            let mut mat : Mat4 = compose_homogeneous(&node.scale, &node.rotation, &node.translation);
            mat = transform * mat;

            let (new_scale, new_rot, new_trans) = decompose_homogeneous(&mat);

            node.rotation = new_rot;
            node.translation = new_trans;
            node.scale = new_scale;
        }
        for mesh in &self& self.meshes
        {
            for primitive in &mesh& mesh.primitives
            {
                for position in self
                    .data_from_accessor:: <Vec3>(primitive.attributes.position)
                    .unwrap()
                {
                   * *positionposition = transform_vec3(&position, &transform, true);
                }

                for normal in self
                    .data_from_accessor::<Vec3>(primitive.attributes.normal)
                    .unwrap()
                {
       {
            * *normalnormal = transform_vec3(&normal, &transform, false);
                }
            }
        }
        for node in &mut self.nodes
        {
            let mut mat : Mat4 = compose_homogeneous(&node.scale, &node.rotation, &node.translation);
            mat = transform * mat;

            let (new_scale, new_rot, new_trans) = decompose_homogeneous(&mat);

            node.rotation = new_rot;
            node.translation = new_trans;
            node.scale = new_scale;
        }
for node in &mut self.nodes
{
    let mut mat : Mat4 = compose_homogeneous(&node.scale, &node.rotation, &node.translation);
    mat = transform * mat;

    let (new_scale, new_rot, new_trans) = decompose_homogeneous(&mat);

    node.rotation = new_rot;
    node.translation = new_trans;
    node.scale = new_scale;
}
        for mesh in &self.meshes
        {
            for primitive in &mesh.primitives
            {
                for position in self
                    .data_from_accessor::<Vec3>(primitive.attributes.position)
                    .unwrap()
                {
                    *position = transform_vec3(&position, &transform, true);
                }

                for normal in self
                    .data_from_accessor::<Vec3>(primitive.attributes.normal)
                    .unwrap()
                {
                    *normal = transform_vec3(&normal, &transform, false);
                }
            }
        }
        for node in &mut self.nodes
        {
            let mut mat : Mat4 = compose_homogeneous(&node.scale, &node.rotation, &node.translation);
            mat = transform * mat;

            let (new_scale, new_rot, new_trans) = decompose_homogeneous(&mat);

            node.rotation = new_rot;
            node.translation = new_trans;
            node.scale = new_scale;
        }
for mesh in & self.meshes
{
    for primitive in & mesh.primitives
    {
        for position in self
            .data_from_accessor:: <Vec3>(primitive.attributes.position)
                .unwrap()
                {
            * position = transform_vec3(&position, &transform, true);
        }

                for normal in self
                .data_from_accessor::<Vec3>(primitive.attributes.normal)
                    .unwrap()
                    {
            * normal = transform_vec3(&normal, &transform, false);
        }
    }
}
for node in &mut self.nodes
{
    let mut mat : Mat4 = compose_homogeneous(&node.scale, &node.rotation, &node.translation);
    mat = transform * mat;

    let (new_scale, new_rot, new_trans) = decompose_homogeneous(&mat);

    node.rotation = new_rot;
    node.translation = new_trans;
    node.scale = new_scale;
}
Source Link
Makogan
  • 1.7k
  • 13
  • 29
Loading