Don't click here unless you want to be banned.

LSL Wiki : LibraryRotationFunctions

HomePage :: PageIndex :: RecentChanges :: RecentlyCommented :: UserSettings :: You are crawl801.us.archive.org

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>;
}



v/=2;
rotation k = <0.0, 0.0, llSin(v.z), llCos(v.z)> * <0.0, llSin(v.y), 0.0, llCos(v.y)> * <llSin(v.x), 0.0, 0.0, llCos(v.x)>;

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 ) {
    return a*llAxisAngle2Rot(llRot2Axis(b/a)*a, llAngleBetween(a, b)*f);
}

//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
Comments [Hide comments/form]
Attach a comment to this page: