Jump to content

Rotation Math Global to Local


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

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

Recommended Posts

Hi Everyone,

I am trying to work on some furniture and I am having trouble wrapping my head around rotation math I need for it.

I have a "Helper" object that can be rotated and subsequently rotates the avatar on the furniture.  It reports how much it has rotated to the main script which then adjusts the avatar the same amount.

I have adjusting the position working fine and adjusting the rotation works fine when the main object's rotation is <0, 0, 0>.

The trouble comes when the main object is rotated.  I am rotating the helper object in the X direction (for example) but the avatar is rotating in the Y direction (also for example, depending on the furniture's root prim is rotated).

I know that there is some rotation math that needs to be done to the incoming rotation but I just can't figure out what that math is.

Note: I have been working in vectors but if things are explained in more general terms or in rotations I can probably convert between them.

To summarize:
- I have an incoming rotation vReported which is a delta rotation in Global co-ordinates.
- I have the current rotation of the avatar sitting on the furniture vAvatar in Local co-ordinates.
- I have the current rotation of the furniute root prim vObject in Global co-ordinates.
- The new avatar position = vAvatar + (vReported <Somehow convered to local co-ordinates with vObject>).  Can someone help me understand how to do this step?


Link to comment
Share on other sites

In general, to translate a rotation by an object's frame of reference (in front of me, to my left) rather than by the region's (to the north of me, to the west of me) you "multipy" it by the object's rotation.   Scare quotes because I don't find it at all helpful to consider the operation as multiplication -- in this context you're translating the rotation.

So, "one metre on the positive x axis of this prim, no matter how the prim is rotated" is


If you want to rotate something using the object's frame of reference, you would use something like this:


One reason why it's not helpful, by the way, to use the term "multiply" is that, when you're calculating rotations, the order of the operations is very important.   If you want to translate the rotation by the object's rotation, it has to be written that way.

rotation grX45;//define a constantdefault{	state_entry()	{		grX45=llEuler2Rot(<-45.0,0.0,0.0>*DEG_TO_RAD);			}	touch_start(integer total_number)	{		llSetRot(grX45*llGetRot()); //move -45 degrees on my X axis (clockwise)	}}

llSetRot(llGetRot()*grX45 ) means something completely different, as you will see if you try it.

However, I'm a little unsure what you're actually trying to do.   If you simply want to rotate the avatar's sit target, then the rotation element in llSitTarget is local to the prim anyway.  

If you actually want to rotate the avatar after she's been seated, then you need to use llSetLinkPrimitiveParamsFast.   You then have a choice between PRIM_ROTATION and PRIM_ROT_LOCAL.   I would use PRIM_ROT_LOCAL because it's simpler (and because PRIM_ROTATION is famously buggy in child prims: see SVC 93).  

So if you want to move the seated avatar 45 degrees clockwise and anti-clockwise, you would need to do something like:

rotation grZ45;//define a constantdefault{    state_entry()    {        llSitTarget(<0.0,0.0,0.25>,ZERO_ROTATION);//define a sit target (looking straight ahead)        grZ45=llEuler2Rot(<0.0,0.0,-45.0>*DEG_TO_RAD);//45 degrees clockwise on the object's z axis    }    touch_start(integer total_number)    {                   //if there's someone sitting on me            llSetLinkPrimitiveParamsFast(llGetNumberOfPrims(),[PRIM_ROT_LOCAL, grZ45]);//rotate the avatar by 45 degrees on the root prim's frame of reference            grZ45=ZERO_ROTATION/grZ45;//reverse the rotation for the next click            }    changed(integer change)    {        if(change & CHANGED_LINK){//Someone has sat or stood up            grZ45=llEuler2Rot(<0.0,0.0,-45.0>*DEG_TO_RAD);//reset the rotation        }    }}
Link to comment
Share on other sites

I think I know what you are doing.

What you need is to have the helper object having the same rotation than the root of your furniture. For that your furniture can rez the helper object by using the same rotation. Then you can easily get relative rotation/translations out of it.

If you have different rotations you have 2 different coordinate systems and need quite some calculations to translate between them. The question is: what would be the reason to do this?


Link to comment
Share on other sites

Thanks for the replies Innula and Nova.

Innula, I want to take a rotation in Global co-ordinates, translate it so it is in local co-ordinates and then apply it to a prim (the avatar) on the furniture.

I have tried "rAvatar * rReported * rObject" but it always turns a small reported rotation into a much larger rotation.  I have tried it as "rAvatar * (rReported * rObject)" but that did not help.  I am guessing the (rReported * rObject) translates the reported delta rotation to local co-ordinates, similar to how your "grX45*llGetRot()" applied the 45 degress to the local X axis but no matter how I try it, it is never quite right.  It either increases the size of the rotation drastically or rotates it along the wrong axis.

I have tried using PRIM_ROTATION and it did not work as expected.

I am not sure which part is going wrong.  I just know why I apply the reported translation directly and the furniture's base rotation is not <0, 0, 0> (it is more like <90, 0, 90>) the avatar rotates around the wrong axis.  But when the furniture's base rotation is <0, 0, 0> it works as expected.

Nova, I don't think that is going to solve the problems as expected.  I can't exactly wrap my head around how it is going to work but the helper object would still be reporting that it rotated 5 degrees around the world's X axis, regardless of how it started out.  And it would still need to translate to such a rotation to the avatar's rotation.  Perhaps if the helper object had more than one prim it might help but that is getting complicated too.

Thanks for the ideas though,


I don't think I described what my trouble was in this last edit very well.  I will rotate the helper object 5 degrees in the global co-ordinate system (for example).  When I apply the rotation to the avatar I want to keep applying based on the global co-ordinate system but it always applies it to the local co-ordinate system.

How do I translate the rotation so it will still be the same in the global system when applied to the location co-ordinate system?

Link to comment
Share on other sites

This is the calculation I use when I'm making rezzers.   I'm not being lazy in giving it you like this -- I just think it'll be easier in the long run if you see how I do it and then apply it to what you're doing, since you know what your script looks like and I'd be guessing.    I suspect, for example, you will be reading llGetObjectDetails(SeatedAvUUID,[OBJECT_POS,OBJECT_ROT]) but I don't know.   

If you're using llSetLinkPrimitiveParamsFast (or any related function) and PRIM_ROTATION to move the avatar, do please be aware of SVC-93


vector rezzer_pos =<some vector>;  // the position of the rezzer when first you set it up -- read with llOwnerSay((string)llGetPos());in another scriptrotation rezzer_rot  =<some rotation>; //rotation of the rezzer, ditto --  read with llOwnerSay((string)llGetRot());in another scriptvector child_pos = <some other vector>; // the position of the rezzed object at first set up,rotation child_rot= <some other rotation>;//rotation of rezzed object, at first set upvector offset;default{    state_entry()    {        offset = child_pos-rezzer_pos;        offset = offset/rezzer_rot;    }    touch_start(integer total_number)    {        llRezAtRoot(llGetInventoryName(INVENTORY_OBJECT,0),        llGetPos()+offset*llGetRot(),        ZERO_VECTOR,        (child_rot/rezzer_rot)*llGetRot(),         99);    }}
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 2735 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

  • Create New...