February 15, 2014

Rotation: a one prim door (more)

In the previous posting on this topic, I mentioned in its Note 2 that a single call to llSetPrimitiveParams() would create a visual flaw in which the hinge wobbles.  The flaw is caused by moving the center of the door in a straight line as it rotates.  It is corrected by moving the center of the door in an arc around the hinge point.

This drop-in replacement code for shiftTo() performs the interpolation.

shiftTo( vector pEnd, rotation rEnd ) {
    float swingDuration = 5;            // seconds
    integer nSteps      = 50;           // must be positive. 
    // start at the current location
    vector   pStart = llGetPos();
    rotation rStart = llGetRot();
    // Find the hinge point, get the vector that will swing in an arc
    vector pHinge = pStart + lPhingePoint * rStart;
    vector vecToCenter = pStart - pHinge;
    // Get the angle and axis of the global rotation from start to end
    // Since rEnd = rStart * rDelta, left multiply by the inverse 

    // of rStart to isolate rDelta (note 1)
    rotation rDiff = (ZERO_ROTATION / rStart) * rEnd;
    float angle = llRot2Angle(rDiff);
    vector axis = llRot2Axis(rDiff);
    integer k; for ( k=0; k < nSteps; k++ ) {

        // for each step, calculate an intermediate rotation difference
        // by interpolating the angle and applying it to the fixed axis
        float angleDelta = k * angle / (nSteps-1);
        rotation rDelta = llAxisAngle2Rot(axis,angleDelta);

        // Use the intermediate rotation to rotate the hinge to center vector
        // Use the intermediate rotation to turn the object
        vector p = pHinge + vecToCenter * rDelta;
        rotation r = rStart * rDelta;            // (note 2)
        llSetLinkPrimitiveParamsFast( LINK_THIS, 

                         [ PRIM_POSITION, p, PRIM_ROTATION, r]);
        llSleep( swingDuration/nSteps );

As a bonus the door will slowly open and close. (note 3)

Note 1
I discuss the algebraic manipulation of rotations and inverse rotations in Rotation: Algebra.

Note 2
You may have noticed that in contrast to start_entry() (cf. note 3 in the prior post) the order of rotation multiplication in shiftTo() is reversed, that is, the change in rotation is right multiplied against the starting rotation.

The order is reversed because both of these rotations have values in the global (region) coordinates.

The difference between A*B and B*A is that one ordering corresponds to each rotation occurring in progressively rotated coordinates (as in start_entry()), whereas the other ordering corresponds to all rotations being in the same coordinates (as in shiftTo()).

Note 3
If you wish to add sound effects, I recommend adding calls to llPlaySound() in touch_start().  Place them before and after the appropriate calls to ShiftTo().