Converting quaternion to motor causes candy wrapping

87 Views Asked by At

I have an animated model that I am trying to animate using PGA motors.

The animation mostly works but I am noticing that some of my motors seem to have an angle that is exactly 180 degrees off from what is should be, for example:

enter image description hereenter image description here

In between these 2 images the model's leg twists in a single frame, before the twist you can see some weird deformation along the leg, after the twist the leg looks ok.

A perhaps clearer example:

enter image description here

In here you can see the tibia pointing in the exact opposite direction it should.

This is how I am turning my data into motors:

fn quaternion_to_rotor(rotation : &Quatf) -> MultiVec3D
{
    let mut rot = MultiVec3D::zero();
    *rot.s_mut() = rotation.coords.w;
    *rot.e23_mut() = -rotation.coords.x;
    *rot.e31_mut() = -rotation.coords.y;
    *rot.e12_mut() = -rotation.coords.z;

    rot
}

fn vector_to_translator(trans : &Vec3) -> MultiVec3D
{
    let mut translator = MultiVec3D::zero();
    *translator.e01_mut() = -0.5 * trans.x;
    *translator.e02_mut() = -0.5 * trans.y;
    *translator.e03_mut() = -0.5 * trans.z;
    *translator.s_mut() = 1.0;

    translator
}

I trust the data and I mostly trust the code, I suspect that there is an ambiguity as to how quaternions can be turned into motors. My understanding is that quaternions can only represent the shortest rotation around an axis but rotors can represent either, so I think what might be happening is that sometimes I get the short rotation and sometimes I get the long rotation.

Is there a way for me to assert that a rotor is representing the shortest possible rotation around its axis?

Some further exploration shows me that the problem is when I convert matrices to quaternions (for the rotation) I am getting major numerical issues. So the solution seems to be to find a robust matrix to quaternion algorithm.

1

There are 1 best solutions below

0
On BEST ANSWER

The problem ended up being the use of an iterative method to extract the rotation matrix. The proper solution is to use this formula:

https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/

float tr = m00 + m11 + m22

if (tr > 0) { 
  float S = sqrt(tr+1.0) * 2; // S=4*qw 
  qw = 0.25 * S;
  qx = (m21 - m12) / S;
  qy = (m02 - m20) / S; 
  qz = (m10 - m01) / S; 
} else if ((m00 > m11)&(m00 > m22)) { 
  float S = sqrt(1.0 + m00 - m11 - m22) * 2; // S=4*qx 
  qw = (m21 - m12) / S;
  qx = 0.25 * S;
  qy = (m01 + m10) / S; 
  qz = (m02 + m20) / S; 
} else if (m11 > m22) { 
  float S = sqrt(1.0 + m11 - m00 - m22) * 2; // S=4*qy
  qw = (m02 - m20) / S;
  qx = (m01 + m10) / S; 
  qy = 0.25 * S;
  qz = (m12 + m21) / S; 
} else { 
  float S = sqrt(1.0 + m22 - m00 - m11) * 2; // S=4*qz
  qw = (m10 - m01) / S;
  qx = (m02 + m20) / S;
  qy = (m12 + m21) / S;
  qz = 0.25 * S;
}