Experimental Rotation Math Functions
While the default math library
functions are good, they are in no way perfect and are subject to change (and fail due to changes). All math functions will lose precision especially interpolation for
quaternions. Drift will occur with many conversions between Euler and quaternion. These functions will return different results from the base LSL functions, this is due to the fact that the LSL functions work differently.
EulerToRotFast is accurate for about 7 decimal places as compared to
llEuler2Rot.
EulerToRot needs some work; it is supposed to give the more accurate answer of
llEuler2Rot and
EulerToRotFast
RotToEuler is currently a bit more accurate then
llRot2Euler and more sensitive to drift.
WARNING about EulerToRotFast AND EulerToRot
have issues with gimble lock when y=|90| degrees and |x+z|>180
Converts an Euler to a Rotation. Should be equivalent to
llEuler2Rot.
rotation EulerToRotFast(vector v)
{
v/=2;
float ax=llSin(v.x);
float aw=llCos(v.x);
float by=llSin(v.y);
float bw=llCos(v.y);
float cz=llSin(v.z);
float cw=llCos(v.z);
return <aw*by*cz + ax*bw*cw,
aw*by*cw - ax*bw*cz,
aw*bw*cz + ax*by*cw,
aw*bw*cw - ax*by*cz>;
}
Converts an Euler to a Rotation. Error checks
llEuler2Rot and returns the less bugged answer.
rotation EulerToRot(vector v)
{
float err=0.00001;
v/=2;
float ax=llSin(v.x);
float aw=llCos(v.x);
float by=llSin(v.y);
float bw=llCos(v.y);
float cz=llSin(v.z);
float cw=llCos(v.z);
rotation a=<0.0, 0.0, cz, cw>*<0.0, by, 0.0, bw>*<ax, 0.0, 0.0, aw>;
rotation b = <ax*bw*cw + aw*by*cz,
aw*by*cw - ax*bw*cz,
aw*bw*cz + ax*by*cw,
aw*bw*cw - ax*by*cz>;
rotation c = a + b;//this is probably the only time you will see the addition
rotation d = a - b;//and subtraction operators properly used on quaternions.
if( (llFabs(c.x)>err && llFabs(d.x)>err) ||
(llFabs(c.y)>err && llFabs(d.y)>err) ||
(llFabs(c.z)>err && llFabs(d.z)>err) ||
(llFabs(c.s)>err && llFabs(d.s)>err) )
return b;
return a;
}
Converts a Rotation to a Euler. Should be equivalent to
llRot2Euler.
vector Rot2Euler(rotation r)
{
vector v = <0.0, 0.0, 1.> * r; // Rotate unit vector on Z. Only X,Z rotations will have effect.
float x = llAtan2(-v.y, v.z); // Calculate X and Y rotations from result.
float m = llSqrt(v.x*v.x + v.y*v.y + v.z*v.z); // Make certain vector is normalized (edge cases cause asin to fail)
float y = llAsin(v.x/m);
// Rotate X unit vector by supplied rotation, then unwind calculated X and Y rotations leaving only Z.
v = <1.0, 0.0, 0.0> * r * <llSin(-x/2.0), 0.0, 0.0, llCos(-x/2.0)> * <0., llSin(-y/2.0), 0., llCos(-y/2.0)>;
float z = llAtan2(v.y, v.x);
return <x, y, z>;
}
While converting from Euler to Rotation this is mathematicly accurate this suffers from gimble lock (set y to PI_BY_TWO) expanding it and simplifying it removes the gimble lock.
EulerToRotFast is the expanded and simplified form. Ironicly the expanded simplifed form isn't as accurate.
EulerToRot compares the answer from both.
Multiplying
Quaternions (
rotations)
rotation MultiplyRot(rotation a, rotation b)
{
float x = a.s*b.x + a.x*b.s + a.y*b.z - a.z*b.y;
float y = a.s*b.y + a.y*b.s + a.z*b.x - a.x*b.z;
float z = a.s*b.z + a.z*b.s + a.x*b.y - a.y*b.x;
float w = a.s*b.s - a.x*b.x - a.y*b.y - a.z*b.z;
return <x,y,z,w>;
}
can be worked out to be
EulerToRotFast by using
quaternions multiplication.
A Euler to rotation function that allows you to tell it the order to use. Using <1,2,3> should return about the same result as
llEuler2Rot.
rotation Euler2Rot(vector in, vector order)
{//careful, will gimbal lock.
in *= 0.5;
list a = llListSort([
order.x, <llSin(in.x), 0.0, 0.0, llCos(in.x)>,
order.y, <0.0, llSin(in.y), 0.0, llCos(in.y)>,
order.z, <0.0, 0.0, llSin(in.z), llCos(in.z)>],
2, FALSE);
in.x = 6;
rotation b;
do
b = llList2Rot(a, ~(integer)(in.x -= 2)) * b;
while(in.x);
return b;
}
//Taken from http://forums.secondlife.com/showthread.php?p=536622
rotation slerp( rotation a, rotation b, float f ) {
float angleBetween = llAngleBetween(a, b);
if ( angleBetween > PI )
angleBetween = angleBetween - TWO_PI;
return a*llAxisAngle2Rot(llRot2Axis(b/a)*a, angleBetween*f);
}
Copyright status of functions:
All functions on this page are released into public domain and may have been based off other public domain works.
Disclamer:
I do not have a degree in higher mathematics. Please use this as reference, and do plenty of testing. -
BW
rotation torot(vector raw)
{
raw *= DEG_TO_RAD; //convert to radians
rotation quat = llEuler2Rot(raw); //convert to quaternion
return(quat);//return rotation
}
raw = Vector to be converted;
This simply returns the rotation value of raw. - Andrew Montagne
Not efficient, better to just inline
llEuler2Rot(raw * DEG_TO_RAD) -
BW
ScriptLibrary