Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Incremental Rotation with llSetRot()

Caoimhe Armitage
Script Witch
Join date: 7 Sep 2004
Posts: 117
02-16-2005 04:25
Does anybody know a way to compute the quaternion increments between two rotations? Specifically, I'm thinking of a rotational analogy to the usual tricks performed when animating motion using llSetPos(), where you divide the distance between two positions into equal parts.

I do know how to get the 'distance' between two rotations, but it is not entirely clear to me how to determine the unit rotation pointing in the direction 'towards' the target rotation. OTOH, it could be that my quaternophobia is keeping me from thinking clearly about this :)

Any and all help appreciated

- C
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-16-2005 04:47
google
"SLERP Quaternion"
"Spherical Linear Interpolation"


If you know C++ and are fealing ambitions you could rewrite portions of the code found here.
http://www.math.ucsd.edu/~sbuss/ResearchWeb/spheremean/

or impliment this...
http://64.233.167.104/search?q=cache:2Q-qvFh-diMJ:www.plunk.org/~hatch/rightway.php&hl=en


taken from http://www.gametutorials.com/gtstore/pc-79-8-md3-animation.aspx
rewrite
CODE

CQuaternion CQuaternion::Slerp(CQuaternion &q1, CQuaternion &q2, float t)
{
// Create a local quaternion to store the interpolated quaternion
CQuaternion qInterpolated;

// This function is the milk and honey of our quaternion code, the rest of
// the functions are an appendage to what is done here. Everyone understands
// the terms, "matrix to quaternion", "quaternion to matrix", "create quaternion matrix",
// "quaternion multiplication", etc.. but "SLERP" is the stumbling block, even a little
// bit after hearing what it stands for, "Spherical Linear Interpolation". What that
// means is that we have 2 quaternions (or rotations) and we want to interpolate between
// them. The reason what it's called "spherical" is that quaternions deal with a sphere.
// Linear interpolation just deals with 2 points primarily, where when dealing with angles
// and rotations, we need to use sin() and cos() for interpolation. If we wanted to use
// quaternions for camera rotations, which have much more instant and jerky changes in
// rotations, we would use Spherical-Cubic Interpolation. The equation for SLERP is this:
//
// q = (((b.a)^-1)^t)a
//
// Go here for an a detailed explanation and proofs of this equation:
//
// http://www.magic-software.com/Documentation/quat.pdf
//
// Now, Let's code it

// Here we do a check to make sure the 2 quaternions aren't the same, return q1 if they are
if(q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w)
return q1;

// Following the (b.a) part of the equation, we do a dot product between q1 and q2.
// We can do a dot product because the same math applied for a 3D vector as a 4D vector.
float result = (q1.x * q2.x) + (q1.y * q2.y) + (q1.z * q2.z) + (q1.w * q2.w);

// If the dot product is less than 0, the angle is greater than 90 degrees
if(result < 0.0f)
{
// Negate the second quaternion and the result of the dot product
q2 = CQuaternion(-q2.x, -q2.y, -q2.z, -q2.w);
result = -result;
}

// Set the first and second scale for the interpolation
float scale0 = 1 - t, scale1 = t;

// Next, we want to actually calculate the spherical interpolation. Since this
// calculation is quite computationally expensive, we want to only perform it
// if the angle between the 2 quaternions is large enough to warrant it. If the
// angle is fairly small, we can actually just do a simpler linear interpolation
// of the 2 quaternions, and skip all the complex math. We create a "delta" value
// of 0.1 to say that if the cosine of the angle (result of the dot product) between
// the 2 quaternions is smaller than 0.1, then we do NOT want to perform the full on
// interpolation using. This is because you won't really notice the difference.

// Check if the angle between the 2 quaternions was big enough to warrant such calculations
if(1 - result > 0.1f)
{
// Get the angle between the 2 quaternions, and then store the sin() of that angle
float theta = (float)acos(result);
float sinTheta = (float)sin(theta);

// Calculate the scale for q1 and q2, according to the angle and it's sine value
scale0 = (float)sin( ( 1 - t ) * theta) / sinTheta;
scale1 = (float)sin( ( t * theta) ) / sinTheta;
}

// Calculate the x, y, z and w values for the quaternion by using a special
// form of linear interpolation for quaternions.
qInterpolated.x = (scale0 * q1.x) + (scale1 * q2.x);
qInterpolated.y = (scale0 * q1.y) + (scale1 * q2.y);
qInterpolated.z = (scale0 * q1.z) + (scale1 * q2.z);
qInterpolated.w = (scale0 * q1.w) + (scale1 * q2.w);

// Return the interpolated quaternion
return qInterpolated;
}
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Azelda Garcia
Azelda Garcia
Join date: 3 Nov 2003
Posts: 819
02-16-2005 05:24
Thats one way.

Personally Id do what Andrew said in his presentation in ~2003ish:

CODE

InverseRotOne = RotOne;
InverseRotOne.z = - InverseRotOne.z;

RotBetweenStartAndFinish = RotTwo * InverseRotOne;

RotateAxis = llRot2Axis( RotBetweenStartAndFinish );
RotateAngle = llRot2Angle( RotBetweenStartAndFinish );

AngleIncrement = RotateAngle / NumberSteps;

for( Angle = 0; Angle <= RotateAngle; Angle += AngleIncrement )
{
llRotLookAt( RotOne * llAxisAngle2Rot( RotateAxis, Angle ) );
}



There are two things that Linden did well from a technical point of view: one is the streaming is really really good. The other is they use quaternions.
Caoimhe Armitage
Script Witch
Join date: 7 Sep 2004
Posts: 117
02-16-2005 06:15
Thanks for two very interesting responses!

- C
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
02-16-2005 12:40
There should be two functions in the script library that do this, look for "Incremental position and rotation functions" or something similar.
==Chris
Caoimhe Armitage
Script Witch
Join date: 7 Sep 2004
Posts: 117
02-17-2005 19:58
From: Azelda Garcia

Personally Id do what Andrew said in his presentation in ~2003ish:

CODE

...
RotateAxis = llRot2Axis( RotBetweenStartAndFinish );
RotateAngle = llRot2Angle( RotBetweenStartAndFinish );
AngleIncrement = RotateAngle / NumberSteps;

for( Angle = 0; Angle <= RotateAngle; Angle += AngleIncrement ) {
llRotLookAt( RotOne * llAxisAngle2Rot( RotateAxis, Angle ) ); }



Not to look a gift horse in the mouth or anything, but sometimes this picks the wrong direction to rotate. I would like it to always pick the shortest rotatiion. Any ideas?

And BTW, I do find this approach to be fairly elegant in terms of the primitives LSL gives us.

- C
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-17-2005 20:16
I would try doing the calculation twice, but for the second calcuation with the rotations swapped. Think you would need to adjust the sign on the angle for the second calc after that. Then just see which one is smaller.

do know i haven't tested this, it's a total guess.
CODE

RotBetweenStartAndFinish = RotTwo / RotOne;

RotateAxis = llRot2Axis( RotBetweenStartAndFinish );
RotateAngle = llRot2Angle( RotBetweenStartAndFinish );
RotateAngleB = -llRot2Angle( ZERO_ROTATION / RotBetweenStartAndFinish );

If(RotateAngle > -RotateAngleB)
RotateAngle = RotateAngleB;

AngleIncrement = RotateAngle / NumberSteps;

for( Angle = 0; Angle <= RotateAngle; Angle += AngleIncrement )
{
llRotLookAt( RotOne * llAxisAngle2Rot( RotateAxis, Angle ) );
}
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey