Difference between revisions of "User:Pedro Oval/Calculate rotation for pointing in a direction"

From Second Life Wiki
Jump to navigation Jump to search
(Added PointAtHorizViewup2Rot, added examples, fixed a sentence for correctness)
(→‎Examples: PRIM_POS_LOCAL now exists!!)
Line 78: Line 78:


         // Get the target prim's position in local coordinates.
         // Get the target prim's position in local coordinates.
         // This would be simpler if PRIM_POS_LOCAL did exist, which at the time
         vector pos = llList2Vector(llGetLinkPrimitiveParams(2, [PRIM_POS_LOCAL]), 0);
        // of writing this, doesn't.
        //vector pos = llList2Vector(llGetLinkPrimitiveParams(2, [PRIM_POS_LOCAL]), 0);
        vector pos = (llList2Vector(llGetLinkPrimitiveParams(2, [PRIM_POSITION]), 0) - RootPos) / RootRot;


         // Use the world's <0, 0, 1> vector as viewup, after converting it
         // Use the world's <0, 0, 1> vector as viewup, after converting it

Revision as of 16:50, 28 October 2011

Here are two functions that, given a vector to point at, return the rotation that corresponds to that vector.

One of the functions, PointAt2Rot, makes the forward (X) vector point exactly in that direction, while keeping the up (Z) vector pointing "as up as possible". It is similar to what llLookAt does, except that the vector that points to the target is X (forward) instead of Z (up), and the result is a rotation, not a continuously updating state of pointing in the given direction.

The other function, PointAtHoriz2Rot, points to the horizontal that is closest to the given vector, while the up vector points exactly up. It is useful if the final resulting rotation must be horizontal.

<lsl> // Written by Pedro Oval, 2011-01-11

rotation PointAtHoriz2Rot(vector target) {

   // Find the Z rotation:
   return llRotBetween(<1., 0., 0.>, <target.x, target.y, 0.>);

}

rotation PointAt2Rot(vector target) {

   // Find the Z rotation:
   rotation r = PointAtHoriz2Rot(target);
   // Find the Y rotation and multiply it with the Z one:
   return llRotBetween(<1., 0., 0.>, target/r) * r;

} </lsl>

The following are versions of llPointAt2Rot and llPointAtHoriz2Rot that allow a viewup vector (the vector that determines the tilting) expressed in the same coordinate system as the target vector:

<lsl> // Written by Pedro Oval, 2011-01-08

rotation PointAtViewup2Rot(vector target, vector viewup) {

   vector fwd = llVecNorm(target);
   vector left = llVecNorm(viewup % target);
   vector up = fwd % left;
   return llAxes2Rot(fwd, left, up);

}

rotation PointAtHorizViewup2Rot(vector target, vector viewup) {

   vector up = llVecNorm(viewup);
   vector left = llVecNorm(viewup % target);
   vector fwd = left % up;
   return llAxes2Rot(fwd, left, up);

} </lsl>

Examples

The following are incomplete examples, as they need the above functions included, which have been stripped for brevity and ease of maintenance.

This example uses a 0.5 second sensor to detect a nearby prim called Target and makes the current prim's X axis point to it (assuming it's in a prim alone, or in the root of a linked set): <lsl> default {

   state_entry()
   {
       llSensorRepeat("Target", "", ACTIVE | PASSIVE, 30., PI, 0.5);
   }
   sensor(integer num)
   {
       llSetRot(PointAt2Rot(llDetectedPos(0) - llGetPos()));
   }

} </lsl>

The following example shows how to use PointAtViewup2Rot to orient the prim's top in world coordinates, when the script is used within a linked prim. It is assumed to be in a prim with a link number greater than 2. It detects the position of the prim with link number 2 using a timer, and makes this prim's X axis point towards it, and the Z axis as close to the world's up vector as possible: <lsl> default {

   state_entry()
   {
       llSetTimerEvent(0.5);
   }
   timer()
   {
       vector RootPos = llGetRootPosition();
       rotation RootRot = llGetRootRotation();
       // Get the target prim's position in local coordinates.
       vector pos = llList2Vector(llGetLinkPrimitiveParams(2, [PRIM_POS_LOCAL]), 0);
       // Use the world's <0, 0, 1> vector as viewup, after converting it
       // to local coordinates:
       llSetLocalRot(PointAtViewup2Rot(pos - llGetLocalPos(), <0., 0., 1.> / RootRot));
   }

} </lsl>