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

From Second Life Wiki
Jump to navigation Jump to search
(→‎Examples: PRIM_POS_LOCAL now exists!!)
(Change formulation to a less expensive one to calculate, especially for PointAtHoriz2Rot; optimize; change order; eliminate dependency; some text changes)
Line 8: Line 8:
// Written by Pedro Oval, 2011-01-11
// Written by Pedro Oval, 2011-01-11


rotation PointAtHoriz2Rot(vector target)
rotation PointAt2Rot(vector target)
{
{
     // Find the Z rotation:
     // Find the Z rotation:
     return llRotBetween(<1., 0., 0.>, <target.x, target.y, 0.>);
     rotation r = llAxisAngle2Rot(<0, 0, 1>, llAtan2(target.y, target.x));
    // Find the Y rotation and multiply it with the Z one:
    target /= r; // Rotate the vector to the XZ plane
    return llAxisAngle2Rot(<0, -1, 0>, llAtan2(target.z, target.x)) * r;
}
}


rotation PointAt2Rot(vector target)
rotation PointAtHoriz2Rot(vector target)
{
{
     // Find the Z rotation:
     // Find the Z rotation:
    rotation r = PointAtHoriz2Rot(target);
     return llAxisAngle2Rot(<0, 0, 1>, llAtan2(target.y, target.x));
    // Find the Y rotation and multiply it with the Z one:
     return llRotBetween(<1., 0., 0.>, target/r) * r;
}
}
</lsl>
</lsl>
Line 30: Line 31:
rotation PointAtViewup2Rot(vector target, vector viewup)
rotation PointAtViewup2Rot(vector target, vector viewup)
{
{
     vector fwd = llVecNorm(target);
     // Reuse the variables to avoid declaring locals, which is expensive
     vector left = llVecNorm(viewup % target);
    viewup = llVecNorm(viewup % target);
    vector up = fwd % left;
     target = llVecNorm(target);
     return llAxes2Rot(fwd, left, up);
     return llAxes2Rot(target, viewup, target % viewup);
}
}


rotation PointAtHorizViewup2Rot(vector target, vector viewup)
rotation PointAtHorizViewup2Rot(vector target, vector viewup)
{
{
     vector up = llVecNorm(viewup);
     // Reuse the variables to avoid declaring locals, which is expensive
     vector left = llVecNorm(viewup % target);
    target = llVecNorm(viewup % target);
    vector fwd = left % up;
     viewup = llVecNorm(viewup);
     return llAxes2Rot(fwd, left, up);
     return llAxes2Rot(target % viewup, target, viewup);
}
}
</lsl>
</lsl>
When these two functions are passed a viewup of <code>&lt;0, 0, 1&gt;</code>, they return the same result as the former two (except for possible precision issues).


== Examples ==
== Examples ==
Line 63: Line 66:
}
}
</lsl>
</lsl>
Changing <code>PointAt2Rot</code> to <code>PointAtHoriz2Rot</code> in the above will make the prim be always horizontal but with its X face facing the target as much as possible while keeping the horizontality.


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:
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:
Line 82: Line 87:
         // 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
         // to local coordinates:
         // to local coordinates:
         llSetLocalRot(PointAtViewup2Rot(pos - llGetLocalPos(), <0., 0., 1.> / RootRot));
         llSetLocalRot(PointAtViewup2Rot(pos - llGetLocalPos(), <0, 0, 1> / RootRot));
     }
     }
}
}
</lsl>
</lsl>

Revision as of 06:17, 6 November 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 PointAt2Rot(vector target) {

   // Find the Z rotation:
   rotation r = llAxisAngle2Rot(<0, 0, 1>, llAtan2(target.y, target.x));
   // Find the Y rotation and multiply it with the Z one:
   target /= r; // Rotate the vector to the XZ plane
   return llAxisAngle2Rot(<0, -1, 0>, llAtan2(target.z, target.x)) * r;

}

rotation PointAtHoriz2Rot(vector target) {

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

} </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) {

   // Reuse the variables to avoid declaring locals, which is expensive
   viewup = llVecNorm(viewup % target);
   target = llVecNorm(target);
   return llAxes2Rot(target, viewup, target % viewup);

}

rotation PointAtHorizViewup2Rot(vector target, vector viewup) {

   // Reuse the variables to avoid declaring locals, which is expensive
   target = llVecNorm(viewup % target);
   viewup = llVecNorm(viewup);
   return llAxes2Rot(target % viewup, target, viewup);

} </lsl>

When these two functions are passed a viewup of <0, 0, 1>, they return the same result as the former two (except for possible precision issues).

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>

Changing PointAt2Rot to PointAtHoriz2Rot in the above will make the prim be always horizontal but with its X face facing the target as much as possible while keeping the horizontality.

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>