Quaternion rips and tricks
|
|
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
|
11-23-2007 00:19
From: Teddy Qinan Thanks for the compass scripts, they do work well. Although I don't think I explained myself properly. I was meaning compass direction in degrees, and hoping for a combination of functions that would spit out a straight number and save me from having to use If statements to check for which quarter of the compass the prim was pointing. Maybe it can't be done? sure it can, instead of converting the z value to a specific point, you can just offset it. normal output is +/- 180, with zero facing east, if you wanted a range of [0-360) with 0 being north you'd use a formula like this rot-in-deg.z - 90; //-- fixed to north = 0 if (rot-in-deg < 0){ rot-in-deg += 360; //-- }
_____________________
| | . "Cat-Like Typing Detected" | . This post may contain errors in logic, spelling, and | . grammar known to the SL populace to cause confusion | | - Please Use PHP tags when posting scripts/code, Thanks. | - Can't See PHP or URL Tags Correctly? Check Out This Link... | - 
|
|
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
|
11-23-2007 08:56
Use llRot2Fwd to get a unit vector representing the object's direction. Zero out the z component and re-normalize the vector. Take the dot product with due north, <0,1,0>. The dot product of two unit vectors is the cosine of the angle between them, so take the acos of that. If the y component of the direction vector is negative, then you subtract that from TWO_PI. Convert it to degrees, and bam, there's your compass heading.
vector dir = llRot2Fwd( llGetRot() ); dir.z = 0.0; dir = llVecNorm( dir ); float heading = dir * < 0.0, 1.0, 0.0 >; heading = llAcos( heading );
if( dir.y < 0.0 ) heading = TWO_PI - heading;
heading *= RAD_TO_DEG;
|
|
Bloodsong Termagant
Manic Artist
Join date: 22 Jan 2007
Posts: 615
|
11-23-2007 10:34
this is all very odd...
when i want to get a compass heading, i get the global rot2euler and take the .z value, ignoring the x and y rotations. why are you guys taking the other two and mucking around with all that math??
0 is due east, btw, and pi is due west. now dont ask me which of north and south is positive and negative pi_by_two. :X
(im also not responsible for mixing up pi and two_pi. pi is 180, ainnit? 2*pi is 360?)
_____________________
Why Johnny Can't Rotate: http://forums.secondlife.com/showthread.php?t=94705
|
|
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
|
11-23-2007 14:27
From: Bloodsong Termagant why are you guys taking the other two and mucking around with all that math?? Because ignoring the other two axes' rotations can't always be trusted. Build a box, and rotate it -45 on the global Z axis. It's euler rotation, in degrees, will be <0, 0, -45>. Now rotate it 180 on it's local X axis. It's euler rotation is now <-180, 0, 45>. It's local X axis points in exactly the same direction, but it's "compass reading" is now on the wrong side of due East. From: someone pi is 180, ainnit? 2*pi is 360? You're correct on that point.
|
|
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
|
11-23-2007 22:14
good catch Deanna although the numers are off (-45 (SE) is preserved, which is the problem). I'm used to dealing with av's not objects, seems a simplfication based on a point 1m object forward (<1, 0, 0>  would solve that though, but then you have to calculate the angle between your point and center. it should be possible to use the built in rotation to do this, rather than the rot2* functions... and rot2Left(north) is probably more useful than rot2fwd(east)
_____________________
| | . "Cat-Like Typing Detected" | . This post may contain errors in logic, spelling, and | . grammar known to the SL populace to cause confusion | | - Please Use PHP tags when posting scripts/code, Thanks. | - Can't See PHP or URL Tags Correctly? Check Out This Link... | - 
|
|
Soen Eber
Registered User
Join date: 3 Aug 2006
Posts: 428
|
03-04-2008 07:50
A snippet I came up with for following an AV, while keeping rotated towards them. This isn't the complete code; you won't be able to just plug it into an object and sell it -- but there's enough here for an OK scripter to chew on. vector offset = <0.5, 0.0, 2.0>; // follow a litle above and behind key id_follow = NULL_KEY; // load this with the id of the person you are following vector avPosPrev; vector axis = <1.0,0.0,0.0>;
default { state_entry() { llSetStatus( STATUS_ROTATE_X | STATUS_ROTATE_Y | STATUS_ROTATE_Z, TRUE); llRotLookAt(ZERO_ROTATION, 1.0, .01); llSetStatus(STATUS_PHYSICS, TRUE); llSleep(0.1); llSetTimerEvent(0.5); } timer() { list a; vector avPos; rotation avRot;
else { a = llGetObjectDetails(id_follow, ([OBJECT_POS, OBJECT_ROT])); avPos = llList2Vector(a,0); avRot = llList2Rot(a,1); if (llVecDist(avPos, avPosPrev) > 0.5) { rotation rTarget = llRotBetween(axis, avPos - llGetPos()); vector vTarget = llRot2Euler(llRotBetween(axis, llGetPos() - avPos)) * RAD_TO_DEG; // mods to vTarget are dependent on your object's local rotation vTarget.x = 0.0; // clamp x & y keep follower object pointing straight up vTarget.y = 0.0; vTarget.z = vTarget.z + 180; // substitute 180 with whatever works rTarget = llEuler2Rot(vTarget * DEG_TO_RAD); llRotLookAt(rTarget, 1.0, .05); } } llMoveToTarget(avPos + offset, 1); avPosPrev = avPos; } }
|
|
Winter Ventura
Eclectic Randomness
Join date: 18 Jul 2006
Posts: 2,579
|
03-04-2008 08:27
personally, I find it easier to convert to Eulers and degrees... and then back again. That way I can work in a system I understand.
_____________________
 ● Inworld Store: http://slurl.eclectic-randomness.com ● Website: http://www.eclectic-randomness.com ● Twitter: @WinterVentura
|
|
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
|
03-04-2008 18:07
easier, yes, more effecient, no.
_____________________
| | . "Cat-Like Typing Detected" | . This post may contain errors in logic, spelling, and | . grammar known to the SL populace to cause confusion | | - Please Use PHP tags when posting scripts/code, Thanks. | - Can't See PHP or URL Tags Correctly? Check Out This Link... | - 
|
|
Winter Ventura
Eclectic Randomness
Join date: 18 Jul 2006
Posts: 2,579
|
03-04-2008 21:48
All depends on how you define efficiency.
_____________________
 ● Inworld Store: http://slurl.eclectic-randomness.com ● Website: http://www.eclectic-randomness.com ● Twitter: @WinterVentura
|
|
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
|
03-04-2008 22:32
I define it doing the most work with the least effort in the shortest time....
it's not necessary to abandon eulers altogether, but it's certainly alot more effective to know tricks to modify them after turning them to rotations... like multiplying the .s component to reverse the direction of an applied move, or multiplying the .s component by a float being treated as a denominator for the applied degrees, saves doing complicated conversions to and back from eulers for the same operations...
and knowing these tricks up front saves you coding in those extra steps of conversion, makes the code cleaner, run faster, and do less operations to get the same effect...
it's not even necessary to understand how they work 100%, only that they do, and in which situations to apply them.
_____________________
| | . "Cat-Like Typing Detected" | . This post may contain errors in logic, spelling, and | . grammar known to the SL populace to cause confusion | | - Please Use PHP tags when posting scripts/code, Thanks. | - Can't See PHP or URL Tags Correctly? Check Out This Link... | - 
|
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
03-04-2008 23:08
It's better to do rot.s = -rot.s; then to do rot.s *= -1; Doesn't have the same aesthetic but it will be faster and save you some bytecode.
_____________________
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
|
|
Soen Eber
Registered User
Join date: 3 Aug 2006
Posts: 428
|
03-05-2008 06:03
Care to share those tricks, then? this is the thread for it...
I do the conversions mostly because my mental bandwidth is so small; I'm always trying to chop things up into units I can understand and deal with...
|
|
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
|
03-05-2008 08:35
several if not all of them are in the first few pages, and I had built a similar wiki page
but here's a recap of some of the formulas //--convert eulers to rotations(quaternions) vDegChange = <0.0, 00, 90.0>; vRotChange = llEuloer2Rot( vDegChange * DEG_TO_RAD );
//-- convert back vDegChange = llRot2Euler( vRotChange ) * RAD_TO_DEG;
//-- rotating on the global axis newRot = llGetRot() * vRotChange;
//-- rotating on the local axis newRot = vRotChange * llGetRot;
//-- reverse direction on a rotation vRotChange.s = -vRotChange.s //-- (90) becomes (-90)
//-- EDIT: removed angle multiplication/division pending a more accurate solution.
//-- finding the local position of an offset around a rotated object (good for rezzors) offset = <1.0, 0.0, 0.0>; worldPostion = llGetPos() + offset * llGetRot(); //-- always 1m object local +x
//-- rotation of an object around an local axis offset (and facing the point) vRotArc = llEueler2Rot( <0.0, 0.0, 6.0> * DEG_TO_RAD ); //-- how far to travel the circle each move nextPos = llGetPos() + (offset - offset * vRotArc) * llGetRot(); nextRot = vRotArc * llGetRot();
//-- rotation of an object around global axis offset (and not facing the point) vRotArc = llEueler2Rot( <0.0, 0.0, 6.0> * DEG_TO_RAD ); nextRot; nextPos = llGetPos() + (offset - offset * vRotArc) * (nextRot *= vRotArc);
and my submission for the great compass debate.
//-- safe (I think) compass degrees/points list vLstPoints = ["S", "E", "N", "W", "S"]; vector vPosNorth = <0.0, 1.0, 0.0>; vector vPosForward = <1.0, 0.0, 0.0>; //-- build dependant forward direction at 0-rot vector vPosNeedle = vPosForward * llGetRot(); vPosNeedle.z = 0; vector vDegFromNorth = llRot2Euler( llRotBetween( vPosNorth, vPosNeedle ) ) * RAD_TO_DEG; //-- should only have a z component, which is our answer. llOwnerSay( llList2String( vLstPoints, llRound(vDegFromNorth.z / 90) + 2 ) ); //-- reports north on straight up or straight down.
_____________________
| | . "Cat-Like Typing Detected" | . This post may contain errors in logic, spelling, and | . grammar known to the SL populace to cause confusion | | - Please Use PHP tags when posting scripts/code, Thanks. | - Can't See PHP or URL Tags Correctly? Check Out This Link... | - 
|
|
Seifert Surface
Mathematician
Join date: 14 Jun 2005
Posts: 912
|
03-05-2008 10:43
From: Void Singer //--multiply or divide the degrees of a rotation vRotChange.s *= 2; //-- same as saying (degrees / 2), in this case it = 45deg
This one doesn't look right. All quaternions that are supposed to represent rotations should be unit, meaning that: r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s = 1 If you multiply r.s by 2, it will no longer be unit. See http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_anglesI think q_0 there corresponds to r.s, and so multiplying cos(alpha/2) by 2 does something... but you should be doing a corresponding thing to all of the sin(alpha/2) terms.
_____________________
-Seifert Surface 2G!tGLf 2nLt9cG
|
|
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
|
03-05-2008 12:45
From: Seifert Surface This one doesn't look right. All quaternions that are supposed to represent rotations should be unit, meaning that: r.x * r.x + r.y * r.y + r.z * r.z + r.s * r.s = 1 If you multiply r.s by 2, it will no longer be unit. See http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_anglesI think q_0 there corresponds to r.s, and so multiplying cos(alpha/2) by 2 does something... but you should be doing a corresponding thing to all of the sin(alpha/2) terms. I was about to point out the same thing. IF LSL always normalizes a quaternion when it is applied (through a function or during vector-quaternion "multiplication"  , this might work for a SPECIFIC ROTATION VALUE, like 90 degrees (haven't checked). But it will NOT WORK GENERALLY, and the above normalization should NOT be counted upon. DON'T USE THIS ONE. EDIT: In fact, a rotation of 90 degrees is a good example where this will NOT work. A 90 degree rotation about the x-axis would translate to a quaternion of <1/sqrt(2), 0, 0, 1/sqrt(2)>. Multiplying the s component by two would result in <1/sqrt(2), 0, 0, sqrt(2)>. Normalizing this would result in <1/sqrt(5), 0, 0, 2/sqrt(5)>, which is actually a 53.13... degree rotation about the x-axis.
|
|
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
|
03-05-2008 21:53
I'd been using it in smaller rotations and thought the slight variance was just rounding error, it does work as a good aproximation for under 20deg but didn't realize the difference magnified as it became larger... oops? so definately don't use it for precision reliant objects or large rotations, but it's still useful for small scale approximations
multiplying a rot is easy, just multiply by itself the number of desired times, anyone have a qiuck way to reduce the scale of a rot arbitrarily? I'm currently toying with it (quat maths are not my strong suite obviously) but havent come up with a quick way to say split a 90 by 3 to achieve 30, without converting, or breaking each part down individually?
EDIT: ok seems you can get half a rotation by adding zero rotation to it, if it's only a single axis (such as z=90deg) vRotTest += ZERO_ROTATION;
still working out arbitray divisors and multiple axis'. any help appreciated...
_____________________
| | . "Cat-Like Typing Detected" | . This post may contain errors in logic, spelling, and | . grammar known to the SL populace to cause confusion | | - Please Use PHP tags when posting scripts/code, Thanks. | - Can't See PHP or URL Tags Correctly? Check Out This Link... | - 
|
|
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
|
03-06-2008 16:51
ok, so as far as I've expiremented it would seem that conversion is the only way to divide a rotation.... and averaging them gets even messier...
divide a rotation by 3 //-- skipping conversion to/from degrees because the operation works the same on radians ourRot = llEuler2Rot( llRot2Euler( ourRot ) / 3 ); //-- I'm assuming there's no problem with magnitude on multiple axis here, but I could be wrong
averaging the difference between 2 rots average = llEuler2Rot( (llRot2Euler( rot1 ) + llRot2Euler( 2 )) / 2 ); //-- same assumption as before
neither seems optimal, but they're the best I could figure given that you have to access rotation parts individually in lsl, but can shorcut all of them in euler vectors.
coments?
_____________________
| | . "Cat-Like Typing Detected" | . This post may contain errors in logic, spelling, and | . grammar known to the SL populace to cause confusion | | - Please Use PHP tags when posting scripts/code, Thanks. | - Can't See PHP or URL Tags Correctly? Check Out This Link... | - 
|
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
03-06-2008 17:41
Dividing and averaging rotations like that... that won't return useful results. You want to be using SLERP. https://wiki.secondlife.com/wiki/SlerpJust for FYI. When combining a rotation with a vector (vec * rot) the resulting vectors magnitude will be llVecMag(vec) * (rot.x * rot.x + rot.y * rot.y + rot.z * rot.z + rot.s * rot.s)
_____________________
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
|
|
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
|
03-06-2008 17:43
I would suggest:
rotation scaledRot = llAxisAngle2Rot(llRot2Axis(rot), scale*llRot2Angle(rot));
|
|
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
|
03-06-2008 18:35
thanks for the confirmation on the problem of magnitude, wasn't able to test the previous, and was looking for a simplified solution... guess there isn't a simpler solution....
as I understand the usage of the slerp algorythm it's a fractional step between rotation A and rotation B, so for dividing you'd use ZERO_ROTATION, your rotation to divide, and and the divsor as a fraction (like .25 for 4, essentially 1/4). for averaging youd use the 2 rotations and .5 (or another fraction representing a step between them).... correct?
/me hates quat math, can't remember enough to do it correctly
_____________________
| | . "Cat-Like Typing Detected" | . This post may contain errors in logic, spelling, and | . grammar known to the SL populace to cause confusion | | - Please Use PHP tags when posting scripts/code, Thanks. | - Can't See PHP or URL Tags Correctly? Check Out This Link... | - 
|