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

LSL Wiki : ChildRotation

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

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:
SetLocalRot(rotation localrot) {
    llSetRot(localrot / ( (ZERO_ROTATION / llGetLocalRot()) * llGetRot()));
}
Notes:

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:

out(string message) {
    llOwnerSay((string) llGetLinkNumber() + "> " + message);
}

vector deg(rotation rot) {
    vector eul = llRot2Euler(rot);
    eul *= RAD_TO_DEG;
    return eul;
}

default {
    touch_start(integer count) {
        if (llDetectedKey(0) != llGetOwner()) return;
    
        out("llGetRot: " + (string) deg(llGetRot()));
        out("llGetLocalRot: " + (string) deg(llGetLocalRot()));
        out("llGetRootRotation: " + (string) deg(llGetRootRotation()));
    }
}

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
There are 3 comments on this page. [Display comments/form]