Exploring offset rotations for a single prim/mesh, and for child prims within a linkset

Soen Eber

Vatican mole
VVO Supporter 🍦🎈👾❤
Joined
Sep 20, 2018
Messages
3,901
((This function is ripped and derived from a post by someone familiar to many oldbies here, but I forgot who and I didn’t carry the attribution forward. I’m sorry, I didn’t expect the code to survive in nearly it’s original form))

Offset Rotation uses this function, which takes two vector values representing a Euler rotation and a positional offset:
Code:
pOffset_rotate(vector vArgRotArc, vector vArgPosOffset)
{
    rotation vRotArc       = llEuler2Rot(vArgRotArc * DEG_TO_RAD );
    vector   vPosOffset     = vArgPosOffset;
    vector   vPosRotOffset  = vPosOffset * vRotArc;
    vector   vPosOffsetDiff = vPosOffset - vPosRotOffset;
    vector   vPosRotDiff    = vPosOffsetDiff * llGetRot();
    vector   vPosNew        = llGetPos() + vPosRotDiff;
    rotation vRotNew        = vRotArc * llGetRot();

    llSetPrimitiveParams([
        PRIM_POSITION, llGetPos() + (vPosOffset - vPosOffset * vRotArc) * llGetRot(),
        PRIM_ROTATION, vRotArc * llGetRot()
    ]);
}
Where both rotation and offset are expressed as vectors,and have two zero values and one non-zero value, and an object is a single prim whose size is one meter cubed,

and where a rotation constant for each slot is expressed as a 360 degree rotation, +/-:

and an offset is ½ the scalar value of the prim for the respective XYZ value, +/-:

And any reference to prim also applies to Meshes:

Findings:
A When the rot and the offset share the same axis, rotation is centered on that axis; it does not rotate on a face
Example: rot = <0.0, 0.0, 30.0>, offset = <0.0, 0.0, 0.5> centers on the Z axis
B A positve offset rotates on the matching + face, a negative offset rotates on the matching – face
Example: <0.0, 0.5, 0.0> spins on the +Y face
Example: <0.0, -0.5, 0.0> spins on the -Y face
C A rot spins on it’s respective axis.
Example: <30.0, 0.0, 0.0> spins on the X axis
Note: because the value is positive, it also spins counter-clockwise
D A positive rot spins counter-clockwise when facing the + face of the prim, and a negative rot spins clockwise when facing the + face of the prim.
Example: <30.0, 0.0, 0.0> spins counter-clockwise on the X axis
Example: <-30.0, 0.0, 0.0> spins clockwise on the X axis
A Rotation governs (1) the magnitude of the rotation, (2) the direction of the rotation, and (3) the axis of rotation:
Magnitude is determined from the absolute value of the rotation
Direction is determined by the +/- attribute of the value: + spins CCW, - spins CW
Axis is determined by whether the rotation value is X (X axis), Y (Y axis), or Z (Z axis)
Example: rot <30.0, 0.0, 0.0> spins 30 degrees CCW on the X axis
Example: rot <0.0, -30.0, 0.0> spins 30 degrees CW on the Y axis
An Offset governs whether the center of rotation is (1) the prim center, or (2) one of it’s faces (aka end points):
When a rotation and an offset have a value in the same XYZ slot, the prim rotatation is from the center of the prim around the respective axis
Example: rot <0.0, 0.0, 30.0>, offset <0.0, 0.0, 0.5> spins CCW around the Z axis from the prim’s center
When a rotation and an offset have values in different XYZ slots, the center of rotation is along the face (aka endpoint) of the respective positve or negative face
Example: rot <-30.0, 0.0, 0.0>, offset <0.0, 0.5, 0.0> spins CW around the Y axis with the center of rotation being the positive Y face (aka endpoint) of the prim
Putting it all together:
  • Determine the clockwise/anti-clockwise direction you wish to offset rotate a prim, and along which axis:
  • For clockwise, make the value negative
  • For anti-clockwise, make the value positive
  • Place the value in the respective XYZ slot of the vector to rotate on that axis

  • Determine the face (or end point) you wish to offset rotate from:
  • The value should be +/- half the scalar value of the respective prim
  • The XYZ slot should correspond to the face you want to offset rotate from, when the prim is viewed in edit mode
  • In edit mode the arrow direction notates the positive side, and vice-versa
 
Last edited:
  • 1Like
Reactions: Noodles

Soen Eber

Vatican mole
VVO Supporter 🍦🎈👾❤
Joined
Sep 20, 2018
Messages
3,901
Followup: Can anyone explain to me how to extend this so instead of a prim offset rotating by itself, the prim would offset rotate from a root prim? I think I have a script I can base from, but it would still be a challenge. Thanks.
 

GoblinCampFollower

Well-known member
Joined
Sep 20, 2018
Messages
5,075
SL Rez
2007
Followup: Can anyone explain to me how to extend this so instead of a prim offset rotating by itself, the prim would offset rotate from a root prim? I think I have a script I can base from, but it would still be a challenge. Thanks.
I admit this is pushing beyond my scripting knowledge in SL, but I suspect there isn't a command to directly rotate from a root prim. You likely have to just include an extra step to set the point of offset to where the root prim is at that moment.
 
  • 1Thanks
Reactions: Soen Eber

Soen Eber

Vatican mole
VVO Supporter 🍦🎈👾❤
Joined
Sep 20, 2018
Messages
3,901
Just finished this one today for child prims in a linkset, but I only performed limited testing due to lack of time. Parameters are the same, only this time the offset is a vector consisting of +/- 1; there is no need to specify an offset value because it is automatically taken from prim scalar values.

Because it's going to be in the mid-to-high 90s this week and probably into the next, I won't be able to function very well while at home due to a lack of air conditioning, and as my genetic make up includes a prominent amount of Sami blood (like laplanders, only my ancestors lived along the Arctic coast) my brain is going to shut down for a couple more weeks from the heat.

On the plus side, I rarely need a jacket in Minneapolis winters.

And again, somebody else did most of the hard work; most of my contributions was cleaning up and organizing the codebase, and rewriting it as a general function with parameterization, thus making it more universal in scope. The only real sweat equity besides the parameterization was reverse-engineering parts of the rotation code to work with rotations expressed as vectors bearing degree values, which is more conceptually intuitive than fugly things I've never really understood like llAngle2Rot() and llRotBetween() and expressing angles in PI*radians and Quaternions. My mind just isn't elegant enough to handle those.

So here's the script, and let me know if you find anything that needs fixing or extending.

To use in-world, rez 2 prims, a cube as root (with the script) and a prim 2 or 3 meters long sitting right on top of it, so it looks something like an exclamation mark (!). You will have to pay attention to where the axis are pointing (x+: front, y+: left, I think, and z+ pointing up (should be the same as when you rez a new prim) and the prims should also have a <0,0,0> rotation, again like a newly rezzed prim would be (I think).

Code:
string _sChild = "rotate me";
integer  _lnChild;

integer lnChild(string sName)
{
    integer i;
    integer n = llGetNumberOfPrims();
    for (i=1; i<=n; i++) {
        if (llGetLinkName(i) == _sChild) {
            return i;
        }
    }
    return 0;
}
do_rot(vector vRot, vector vAxis)
{
    {
        rotation homeRot = llGetRootRotation();   // The root object's sim rotation.
        vector homePos = llGetRootPosition();     // The root object's sim position.

        list params = llGetLinkPrimitiveParams(_lnChild,[PRIM_POSITION,PRIM_ROTATION,PRIM_SIZE]);
        rotation primRot = llList2Rot(params,1)/homeRot;              // The priminder's local rotation.
        vector primPos = (llList2Vector(params,0)-homePos)/homeRot; // The priminder's local position.
        vector primSize = llList2Vector(params,2);                  // The size of the priminder.
      
        vector primHeight = <
            vAxis.x * primSize.x*0.5,
            vAxis.y * primSize.y*0.5,
            vAxis.z * primSize.z*0.5
        > * primRot;
      
        vector pivot = primPos - primHeight;
        rotation newRot = llEuler2Rot(vRot*DEG_TO_RAD);

        vector pivotOffset = <
            vAxis.x * primSize.x*0.5,
            vAxis.y * primSize.y*0.5,
            vAxis.z * primSize.z*0.5
        >*newRot*primRot;
      
        llSetLinkPrimitiveParamsFast(_lnChild,[
            PRIM_ROT_LOCAL,
            newRot*primRot,
            PRIM_POSITION,pivot+pivotOffset
        ]);
    }
}
default
{
    state_entry()
    {
        _lnChild = lnChild(_sChild);
    }
    touch_start(integer total_number)
    {
        do_rot(<45,0,0>, <0,0,1>);
    }
}
 
Last edited: