Anim8or Community

Please login or register.

Login with username, password and session length
Advanced search  

News:

Ian Ross has just released a book on Anim8or. It's perect for a beginner and a good reference for experienced users. It contains detailed chapters on every aspect, with many examples. Get your own copy here: "Anim8or Tutorial Book"

Author Topic: Conversion of jointangle to quaternion  (Read 7200 times)

SomariHater

  • Guest
Conversion of jointangle to quaternion
« on: September 02, 2018, 05:58:45 pm »

I'm trying to figure out how to interpret the joint angles in the sequence section of an8 files. If someone could help me convert the joint angle into a quaternion or a rotation matrix or even XYZ Euler angles, that would be great. (It is okay to assume every keyframe has "X", "Y", and "Z" values for simplicity. I can figure out the interpolation. Also, assume there is just one bone besides the root bone. I can figure out the hierarchy.)

I am trying to reverse engineer it, but I'm getting lost (the an8 spec doesn't say how to interpret the value as far as I can tell). When I set the "Orientation (PYR)" of a bone in figure mode to 0, 45, 45, Anim8or saves a bone orientation quaternion of (0.14645 -0.35355 -0.35355 0.85355) into the figure section of the file. This is what I expect for XYZ Euler angles.

However, if the "Orientation (PYR)" is 0, 0, 0 in figure mode, and I set the "Joint Angles (XYZ)" of a bone in sequence mode to 0, 45, 45, Anim8or displays a very different rotation than figure mode. By manually rotating the bone in sequence mode, I was able to figure out that a "Joint Angle (XYZ)" of 38.5, -61.4, -24.8 produces a similar result to a "Orientation (PYR)" of 0, 45, 45. I attached some pictures to show what I mean.

So, if anyone could help me decode what "Joint Angle (XYZ)" means, that would be awesome. Thanks. Also, if you need more information let me know.
Logged

SomariHater

  • Guest
Re: Conversion of jointangle to quaternion
« Reply #1 on: September 02, 2018, 11:00:28 pm »

I found LibAn8 (https://sourceforge.net/p/liban8/code/HEAD/tree/). It looks like it translates a "Joint Angles (XYZ)" of 0, 45, 45 into the quaternion (0.14645 0.35355 0.35355 0.85355). That is the same as how Anim8or translates a "Orientation (PYR)" of 0, 45, 45 except that the Y and Z positions are positive instead of negative.

That means, LibAn8 claims that an "Orientation (PYR)" of 0, 45, 45 is equivalent to a "Joint Angles (XYZ)" of 0, -45, -45 even though they give different  results in Anim8or. I'm still confused.
« Last Edit: September 03, 2018, 12:12:37 am by SomariHater »
Logged

Raxx

  • Administrator
  • Hero Member
  • *****
  • Posts: 1482
    • View Profile
Re: Conversion of jointangle to quaternion
« Reply #2 on: September 03, 2018, 03:35:58 am »

Have you looked at Steve's writeup here? http://www.anim8or.com/learn/technical/quaternions_and_anim8or/quaternions_and_anim8or.htm This topic has also been brought up a lot in the forums, you may find the answer to what you're looking for in the search results here.
Logged

SomariHater

  • Guest
Re: Conversion of jointangle to quaternion
« Reply #3 on: September 03, 2018, 10:33:08 am »

Yes. I read that, and I've read similar posts like this one: http://www.anim8or.com/smf/index.php/topic,4861.msg35328.html#msg35328. However,  it seems like the writeup doesn't answer this question, and an answer was never determined in that other post.

The angles in figure mode match the writeup and match what I expect for euler angles. For instance, if I increase the "yaw" or angle about the y axis in figure mode, when viewed from the top, the object spins clockwise (which is consistent with the "simple Euler rotations" in the writeup).

However, sequence mode isn't behaving like I expect. For instance, if I increase the angle about the y axis in sequence mode, when viewed from the top, the figure spins counter-clockwise.

In figure mode, if I apply a Y angle of 45 degrees, and a Z angle of 45 degrees, when viewed from the top, the object tilts to the bottom right.

In sequence mode, if I apply a Y angle of 45 degrees, and a Z angle of 45 degrees, when viewed from the top, the object tilts left with a twist.

I'm probably making a stupid mistake somewhere, but the angles don't seem to mean the same thing in figure and sequence mode. I think if the writeup showed how the axes moved in sequence mode and the order of the rotations, then I could understand better.
Logged

Steve

  • Administrator
  • Hero Member
  • *****
  • Posts: 2126
    • View Profile
Re: Conversion of jointangle to quaternion
« Reply #4 on: September 03, 2018, 12:24:35 pm »

The convention that Anim8or uses is:

Looking down an axis in the negative direction, a positive rotation turns clockwise. Some applications do the opposite. Here is a simple axis model and a drawing:

Logged

SomariHater

  • Guest
Re: Conversion of jointangle to quaternion
« Reply #5 on: September 03, 2018, 05:13:12 pm »

Thanks Steve. That helps me clarify a bit. Here's what I've been able to reverse engineer (C# code):

Code: [Select]
   struct Vector
   {
      public double X;
      public double Y;
      public double Z;
   }

   struct Quaternion
   {
      public double X;
      public double Y;
      public double Z;
      public double W;
   }

   // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/
   static Quaternion Multiply(Quaternion a, Quaternion b)
   {
      return new Quaternion
      {
         X = a.X * b.W + a.Y * b.Z - a.Z * b.Y + a.W * b.X,
         Y = -a.X * b.Z + a.Y * b.W + a.Z * b.X + a.W * b.Y,
         Z = a.X * b.Y - a.Y * b.X + a.Z * b.W + a.W * b.Z,
         W = -a.X * b.X - a.Y * b.Y - a.Z * b.Z + a.W * b.W,
      };
   }

   // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
   static Quaternion ToQuaternionFromAxisAngle(Vector axis, double angleDegrees)
   {
      double sin = System.Math.Sin(angleDegrees * System.Math.PI / 180 / 2);
      double cos = System.Math.Cos(angleDegrees * System.Math.PI / 180 / 2);

      return new Quaternion
      {
         X = axis.X * sin,
         Y = axis.Y * sin,
         Z = axis.Z * sin,
         W = cos,
      };
   }

   static Quaternion ToQuaternionFromFigureAngles(double angleDegreesX, double angleDegreesY, double angleDegreesZ)
   {
      // Anim8or rotates clockwise instead of counter-clockwise (confirmed by Steve)
      Quaternion quatX = ToQuaternionFromAxisAngle(new Vector { X = 1, Y = 0, Z = 0 }, -angleDegreesX);
      Quaternion quatY = ToQuaternionFromAxisAngle(new Vector { X = 0, Y = 1, Z = 0 }, -angleDegreesY);
      Quaternion quatZ = ToQuaternionFromAxisAngle(new Vector { X = 0, Y = 0, Z = 1 }, -angleDegreesZ);

      // Anim8or seems to apply -Y then -X then -Z in figure mode
      return Multiply(Multiply(quatY, quatX), quatZ);
   }

   static Quaternion ToQuaternionFromSequenceAngles(double angleDegreesX, double angleDegreesY, double angleDegreesZ)
   {
      // Anim8or rotates counter-clockwise
      Quaternion quatX = ToQuaternionFromAxisAngle(new Vector { X = 1, Y = 0, Z = 0 }, angleDegreesX);
      Quaternion quatY = ToQuaternionFromAxisAngle(new Vector { X = 0, Y = 1, Z = 0 }, angleDegreesY);
      Quaternion quatZ = ToQuaternionFromAxisAngle(new Vector { X = 0, Y = 0, Z = 1 }, angleDegreesZ);

      // Anim8or seems to apply X then Z then Y in sequence mode
      return Multiply(Multiply(quatX, quatZ), quatY);
   }

The above code is not optimized for clarity and simplicity. It looks like in Figure mode Anim8or actually uses -Y-X-Z Euler angles, that is a negative Y rotation is applied first then a negative X rotation then a negative Z rotation. It also looks like in Sequence mode Anim8or uses XZY Euler angles, that is a positive X rotation is applied first then a positive Z rotation then a positive Y rotation. This time I made sure all the signs are correct, and I tested X, Y, and Z angles. In my previous posts I was wrong in some of my statements since I ignored flipped signs and didn't test X rotations.

I will post corrections if I find that I made a mistake. Let me know if you think there is a problem with my sample code.
Logged