Child Rotation
Child rotation is the
rotation of a
child prim in relation to its
parent (instead of in relation to the
world). This comes into play when moving (rotating) parts that are in a linked object that can itself be rotated.
Examples
An example of child rotation is a car door. No matter what direction the car faces, the doors are probably expected to always open outwards and rotate around their hinges.
The usual way of rotation using
llSetRot is always in relation to the world
axis. To make the door rotate in relation to the whole car it is linked to, the relative rotation for the door has to be combined with the current rotation of the whole car (in relation to the world axis). Luckily, the
function llSetLocalRot does exactly that.
Or, if to do it manually for some reason (such as perform a
local rotation with a
llSetPrimitiveParams call), this function does the same:
Notes:
- The / operator rotates the rotation on the left by the inverse of the rotation on the right. It has nothing to do with division.
- This does not work for attachments as llGetLocalRot and llGetRot behave differently when in a prim that is attached to the avatar.
The same in more detail (and with the inverting done manually):
rotation Inverse(rotation r)
{
r.x = -r.x;
r.y = -r.y;
r.z = -r.z;
return r;
}
rotation GetParentRot()
{
return Inverse(llGetLocalRot())*llGetRot();
}
SetLocalRot(rotation x)
{
llSetRot(x*Inverse(GetParentRot()));
}
Note: For child prim of an attachment, use this instead (where
rootrot is rotation of
root prim--use
llMessageLinked to obtain that):
SetLocalRot(rotation localrot) {
llSetRot(localrot / rootrot);
}
To rotate an object in two steps starting at its current orientation:
(1) first
pi/2 about the world's z-axis...
Qz
(2) then pi/2 about the world's x-axis...
Qx
The final rotation would be:
Q = llGetRot() * Qz * Qx;
llSetRot(Q);
Note the order of operations.
To rotate from a current orientation:
(1) first pi/2 about the object's z-axis...
Qz
(2) then pi/2 about the object's x-axis...
Qx
The final rotation would be:
Q = Qx * Qz * llGetRot();
llSetRot(Q);
This last example is useful for when a script computes a small incremental rotation in the object's local frame (call it
dQ) and add that slight rotation to the object's current orientation. Assuming
dQ is known, the script calls that would rotate the object would be:
Q = dQ * llGetRot();
llSetRot(Q);
Below here needs its "you"/"your" reworded. -
EepQuirk
Child Rotation How-To
Now, after that
very exciting math explanation, I'm sure you just want to know how to get down and dirty with how to
actually set up a child linked object for rotation. This portion of the page is dedicated to outlining step-by-step, how to make a child prim rotate.
Step 1: First, you need your basic linked object. Any linked object will do.
Step 2: Rotate your linked object, so that the parent of the set is at
ZERO_ROTATION. In other words, in the edit window, make sure the object's rotation X = 0, Y = 0 and Z = 0.
Step 3: Locate your child object that needs to be rotated. Go into edit mode and check the box next to "Edit Linked Parts". This will allow you to select prims in the set individually
Step 4: Select the target prim, and unlink only it from the set. Now, right click the target prim again. The target prim should now have a gold halo around it, and should be movable seperately from the set.
Step 5: Rotate the target prim to the rotation you want it to be at. Then, put this script into it:
default {
state_entry() {
llSay(0, (string) llGetRot());
}
}
Step 6: Record the value the object said.
Step 7: Repeat steps 5 and 6 until all rotations of the object are covered.
Step 8: Link the child prim back on to the set.
Step 9: Rotate the parent of the set back into its original rotation.
Step 10: When passed the values you got in step 6,
llSetLocalRot will now rotate your child prim correctly, relative to the rotation of the parent prim.
Attachments
Getting things to work out with attachment prim rotations is challenging because of trying to rotate child prims relative to the root prim of the attachment and not the avatar rotation. Here's the breakdown of the various functions in different situations:
script in the root prim of a normal detached object
llGetRot | object global rotation |
llGetLocalRot | object global rotation |
llGetRootRotation | object global rotation |
script in the child prim of a normal detached object
llGetRot | object global rotation + prim rotation |
llGetLocalRot | prim rotation |
llGetRootRotation | object global rotation |
script in root prim of attachment
llGetRot | avatar rotation |
llGetLocalRot | attachment rotation |
llGetRootRotation | avatar rotation |
script in child prim of attachment
llGetRot | avatar rotation + prim rotation (BOGUS) |
llGetLocalRot | prim rotation with respect to the attachment root prim |
llGetRootRotation | avatar rotation |
Basically, what's going with attachments is that the avatar sort of becomes the root prim and replaces its rotations for the attachment root prim rotations.
There's a couple things to take note of here. One is that there's no way to directly tell what the attachment rotation is from a script within an attachment child prim. That makes it a bit hard to make root prim relative adjustments to rotation.
The other is that llGetRot returns a completely bogus value from a script in an attachment child prim because it's actual rotation is
avatar rotation * attachment rotation * prim rotation not
avatar rotation * prim rotation. As the attachment is rotated this value becomes completely meaningless.
For example, create two prims and link them. Set the child to have a rotation of 30 deg in the Z axis. Attach the object to your skull or somewhere appropriate. Then rotate the whole attachment 45 deg in the Z.
Then using this handy script:
You will get results similar to these:
Root 1:
llGetRot: <0.00000, 0.00000, -6.66063>
Root 1:
llGetLocalRot: <0.00000, 0.00000, 45.00000>
Root 1:
llGetRootRotation: <0.00000, 0.00000, -6.66063>
Child 2:
llGetRot: <0.00000, 0.00000, 23.33937>
Child 2:
llGetLocalRot: <0.00000, 0.00000, 30.00000>
Child 2:
llGetRootRotation: <0.00000, 0.00000, -6.66063>
Looking at the child's
llGetRot it is clear that you should be seeing -6.7 + 45.0 + 30.0 = 68.3 and not 23.3 as shown because that's what you are actually observing.
Having
llSetPrimitiveParams use
llSetLocalRot functionality instead of
llSetRot would go a long way toward alleviating this problem. In the mean time there's no easy workaround. Harcoding or passing around the attachment rotation is probably a start.
Functions |
Rotation