Jump to content

Calculating W for a "Truncated Quaternion"


Phate Shepherd
 Share

You are about to reply to a thread that has been inactive for 1323 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I hope I can catch the eye of someone with better math skills than I have...

The SL internal .anim format appears to store rotations as "Truncated Quaternions". Only X, Y and Z are stored, and W is calculated later. From the wiki: http://wiki.secondlife.com/wiki/Internal_Animation_Format

"Note: These three values X Y Z appear to be the first three values of a truncated quaternion with the W term being calculated afterwards. Since a quaternion is X2 + Y2 + Z2 + W2 = 1 as long as you assume the W term has a consistent sign the X Y Z terms will be accurate."

The part I don't understand is the "Consistent Sign". If I have a quaternion value that I want to truncate, how can I make sure the sign is consistent so it can be recreated?

Also, I have long forgotten what the internal rotation order is when LSL converts a Euler to a Rot. Is it X*Y*Z, or some other order?

(I found the answer to the second question: "The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes in Z, Y, X order.")

Edited by Phate Shepherd
  • Like 1
Link to comment
Share on other sites

1 hour ago, Phate Shepherd said:

The part I don't understand is the "Consistent Sign". If I have a quaternion value that I want to truncate, how can I make sure the sign is consistent so it can be recreated?

I assume it means that W should be always positive or always negative. If the values you're plugging in can be of either sign, the results may be undefined.

Edited by Wulfie Reanimator
Link to comment
Share on other sites

1 hour ago, Wulfie Reanimator said:

I assume it means that W should be always positive or always negative. If the values you're plugging in can be of either sign, the results may be undefined.

Thats where I am lost. If it can be negative or positive, how can they be reliably storing a quaternion as 3 values in the .anim without at least storing the sign of the missing W component.

Link to comment
Share on other sites

1 hour ago, Phate Shepherd said:

Thats where I am lost. If it can be negative or positive, how can they be reliably storing a quaternion as 3 values in the .anim without at least storing the sign of the missing W component.

I can't be negative and positive, that's what it's saying.

The way animations are implemented -- the way the rotation data is stored -- assumes that the output XYZ values will always have the same W sign.

To put it another way... W is calculated a certain way. If your input quaternions have mixed Ws, the recalculated output W won't be correct for some of them and won't do what you expect. As long as your inputs are consistent, you can expect consistent outputs.

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

13 minutes ago, Wulfie Reanimator said:

I can't be negative and positive, that's what it's saying.

The way animations are implemented -- the way the rotation data is stored -- assumes that the XYZ values will always have the same W sign.

To put it another way... W is calculated a certain way. If your input quaternions have mixed Ws, the recalculated output W won't be correct for some of them and won't do what you expect. As long as your inputs are consistent, you can expect consistent results.

I think I follow, but that is where I was going. If my input quaternion has a negative W, how do i recalculate the X, Y and Z values to get W to be positive. Trying some experiments.

Link to comment
Share on other sites

3 hours ago, Phate Shepherd said:

I think I follow, but that is where I was going. If my input quaternion has a negative W, how do i recalculate the X, Y and Z values to get W to be positive. Trying some experiments.

That's where I get lost. But considering that this:

vector axis = llVecNorm(<1,1,0>);
float angle = llGetTime() * 45 * DEG_TO_RAD;
llSetRot(llAxisAngle2Rot(axis, angle));

Is equivalent to this: (source: this wiki page and eyeballing in-world)

vector axis = llVecNorm(<1,1,0>);
float angle = llGetTime() * 45 * DEG_TO_RAD;
rotation q;
q.x = axis.x * llSin(angle/2);
q.y = axis.y * llSin(angle/2);
q.z = axis.z * llSin(angle/2);
q.s = llCos(angle/2);
llSetRot(q);

I'm sure you can figure something out.

I know that the original angle can be calculated from a quaternion. The sign of that angle determines the sign of W (or "S" in LSL), meaning that once you have the angle, and if it happens to be negative, you can then adjust it accordingly and calculate the new quaternion from that.

Edited by Wulfie Reanimator
Link to comment
Share on other sites

The SL convention is that w is always nonnegative.

So w is simply 1.0 - sqrt(x*x + y*y + z*z);

If you get a negative w out of that, the quaternion data is invalid.

19 hours ago, Phate Shepherd said:

If my input quaternion has a negative W, how do i recalculate the X, Y and Z values to get W to be positive.

Take the negative of X, Y, Z, and W to make W positive. The result represents the same rotation.

  • Like 1
  • Thanks 2
Link to comment
Share on other sites

I did a test running through random XYZ values, and generated numerous negative W values.

Euler in degrees: <-5.10513, -117.65760, 116.72350>  Rot in radians:  <0.73983, 0.42875, -0.46022, -0.23880>

So, is it likely that when the quaternion was stored truncated that the XYZ were inverted if W was negative, allowing W to be recreated knowing that it will be positive?

I read the notes on the .anim format, and there appears to be some confusion in the format, specifically due to a couple different versions of the format. An early version storing as Euler, and the later as a truncated quaternion.

Link to comment
Share on other sites

Tested and shows animats is corrrect. Thank you.

default
{
    touch_start(integer total_number)
    {
        integer i;
        vector  v;
        rotation r1;
        rotation r2;
        
        for (i=0; i<10; ++i)
        {
            v = <llFrand(360) - 180, llFrand(360) - 180, llFrand(360) - 180>;
            r1 = llEuler2Rot(DEG_TO_RAD * v);
            
            if (r1.s < 0)
            {
                r2.x = -r1.x;
                r2.y = -r1.y;
                r2.z = -r1.z;
                r2.s = -r1.s;
            }
            else r2 = r1;
            
            llOwnerSay((string)(llRot2Euler(r1) * RAD_TO_DEG) + " = " + (string)(llRot2Euler(r2) * RAD_TO_DEG));
        }
    }
}

 

  • Like 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 1323 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...