Jump to content

Rotation question for Quistess


Innula Zenovka
 Share

You are about to reply to a thread that has been inactive for 837 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

I'm trying to use the userfunction 

rotation uVectorRoll2Rot(vector v,float r)
{   return YPR2Rot(<llAtan2(v.y,v.x),-llAtan2(v.z,llVecMag(<v.x,v.y,0>)),r>);
}

from Quistess' very helpful collection in the Script Library, but I'm not too sure what float r represents.

I'm trying to calculate the values to feed llSetKFM when my vehicle is crossing a hump-back bridge.    Or am I doing it all wrong (again)?

  • Like 1
Link to comment
Share on other sites

1 hour ago, Innula Zenovka said:

Possibly so, but since Quistess explains "This will return a rotation that points the local x-axis (the forward vector) to vector v," I'm not sure that's what it does, in fact stand for.

I tried it in-world, and yeah, it's radians.

V is a direction (llVecNorm, basically), R is the roll around that direction.

rotation YPR2Rot(vector v) // Yaw Pitch Roll
{
   return
        <llSin(v.z/2),0,0,llCos(v.z/2)> *
        <0,llSin(v.y/2),0,llCos(v.y/2)> *
        <0,0,llSin(v.x/2),llCos(v.x/2)> ;
}

rotation uVectorRoll2Rot(vector v,float r)
{
   return YPR2Rot(<llAtan2(v.y,v.x),-llAtan2(v.z,llVecMag(<v.x,v.y,0>)),r>);
}

default
{
    state_entry()
    {
        while (1)
        {
            // Direction up, rotate over time
            llSetRot( uVectorRoll2Rot(<0,0,1>, llGetTime()) );
            llSleep(0.066);
        }
    }
}

gif.gif.27d418cc4b636f2f01f41bcb28c42dc5.gif

As you can see, <0,0,1> points toward the Z axis, so this object's local X axis now points towards Z. And since the code is in a loop, it's rotating 1 radian per second around the Z axis.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

7 hours ago, Innula Zenovka said:

rotation uVectorRoll2Rot(vector v,float r) { return YPR2Rot(<llAtan2(v.y,v.x),-llAtan2(v.z,llVecMag(<v.x,v.y,0>)),r>); }

So, there are several different ways to conceptualize a rotation, and getting them confused leads to bad results.

This function is most useful in a 'static rotation' mindset, where you think of the 'rotation' of an object as magically representing its 3 intrinsic axes (the x-y-z lines you see when you edit an object, select move and change to relative rather than world coordinates) and you turn around an object by setting its rotation to have the 3 axes that make sense.

So, what this function does (assuming I wrote it correctly), is give you a rotation that represents the x-axis being vector v, then if you look straight on so that x-axis is pointing straight at you, the y-axis is pointing in a direction r-radians around from the right (so setting r to pi/2 would have the y-axis point straight up, from the perspective of someone looking at the object directly facing its intrinsic x-axis)

for KFM though, you don't want 'static rotations' because KFM works with dynamic or transformational rotations. In the same way you can't feed KFM absolute positions to move to (which would be super useful but alas. . .) you can't feed it absolute orientations. Luckily the transformation from absolute to relative isn't that hard, analogous to how you might use absolute positions:

llSetKeyframedMotion([WhereIWantToBe-WhereIAm,HowLongToGetThere],[KFM_DATA,KFM_TRANSLATION]);

You can take the difference of two rotations by dividing them:

llSetKeyframedMotion([HowIWantToBeOriented/HowIAmOrientedNow,HowLongToLookThere],[KFM_DATA,KFM_ROTATION]);

So, a 'going up a hill' KFM list might look something like:

// strided list translation, rotation, time
list KFM =
[
  <llCos(TWO_PI*(0/8)),llSin(TWO_PI*(0/8)),0>,
  		qVR2R(<llCos(TWO_PI*(0/8)),llSin(TWO_PI*(0/8)),0>),	1.0, // translation should be <1,0,0> or 1 unit forward.
  <llCos(TWO_PI*(1/8)),llSin(TWO_PI*(1/8)),0>, // slightly up
  		qVR2R(<llCos(TWO_PI*(1/8)),llSin(TWO_PI*(1/8)),0>)/qVR2R(<llCos(TWO_PI*(0/8)),llSin(TWO_PI*(0/8)),0>) ,	1.0,
  <llCos(TWO_PI*(2/8)),llSin(TWO_PI*(2/8)),0>, // slightly more up
  		qVR2R(<llCos(TWO_PI*(2/8)),llSin(TWO_PI*(2/8)),0>)/qVR2R(<llCos(TWO_PI*(1/8)),llSin(TWO_PI*(1/8)),0>) ,	1.0,
  <llCos(TWO_PI*(1/8)),llSin(TWO_PI*(1/8)),0>, // only slightly up
  		qVR2R(<llCos(TWO_PI*(1/8)),llSin(TWO_PI*(1/8)),0>)/qVR2R(<llCos(TWO_PI*(2/8)),llSin(TWO_PI*(2/8)),0>) ,	1.0,
  <llCos(TWO_PI*(0/8)),llSin(TWO_PI*(0/8)),0>, // forward (top of the hill) (notice I'm still rotating down at this point)
  		qVR2R(<llCos(TWO_PI*(0/8)),llSin(TWO_PI*(0/8)),0>)/qVR2R(<llCos(TWO_PI*(1/8)),llSin(TWO_PI*(1/8)),0>),	1.0,
  <llCos(TWO_PI*(-1/8)),llSin(TWO_PI*(-1/8)),0>, // slightly down
  		qVR2R(<llCos(TWO_PI*(-1/8)),llSin(TWO_PI*(-1/8)),0>)/qVR2R(<llCos(TWO_PI*(0/8)),llSin(TWO_PI*(0/8)),0>),1.0,
  <llCos(TWO_PI*(-2/8)),llSin(TWO_PI*(-2/8)),0>, // more slightly down
  		qVR2R(<llCos(TWO_PI*(-2/8)),llSin(TWO_PI*(-2/8)),0>)/qVR2R(<llCos(TWO_PI*(-1/8)),llSin(TWO_PI*(-1/8)),0>),1.0,
  <llCos(TWO_PI*(-1/8)),llSin(TWO_PI*(-1/8)),0>, // only slightly down
  		qVR2R(<llCos(TWO_PI*(-1/8)),llSin(TWO_PI*(-1/8)),0>)/qVR2R(<llCos(TWO_PI*(-2/8)),llSin(TWO_PI*(-2/8)),0>),1.0,
  <llCos(TWO_PI*(0/8)),llSin(TWO_PI*(0/8)),0>, // forward (botom of the hill) (still rotating back to normal)
  		qVR2R(<llCos(TWO_PI*(0/8)),llSin(TWO_PI*(0/8)),0>)/qVR2R(<llCos(TWO_PI*(-1/8)),llSin(TWO_PI*(-1/8)),0>),1.0 // no final ','
  // The forum editor is bad and I'm lazy. if you want this to actually work, change all TWO_PI to PI and add a .0 after all the 8's.
];

Of course in this simple case there are more efficient methods for calculating the rotation, and you'd probably want to create that list programmatically rather than writing it out by hand.

also you'll probably notice the way the rotations are staggered isn't ideal. Where the object is looking is always slightly late compared to where it is moving.

1098225453_KFMbadlook.png.e68f1ac9a8f4b6160dffe2080c2857ea.png (pray excuse my bad mouse-writing)

Ideally we want to be looking sort of half-way between the direction we just moved from and the direction we're about to move. Luckily, that's just the sum of the next two translations:

751950221_KFMbadlook2.png.041f6361a423c36a1ccb470de2c5dd6f.png

So, I'm too lazy to code a general-purpose KFM fixer, but more or less how I would do it:

  • generate a list of points to move between. (depending on your application could skip this and do the next step directly)
  • take the difference between consecutive points to create a list of translations (call it listTranslation)
  • either take the sum of consecutive translations, or the difference of points 2 appart (point 2-0, 3-1,4-2...) and make a new list (listNormal)
  • use uVectorRoll2Rot or similar to convert each vector in listNormal into a rotation. (listAbsoluteRots)
  • take the quotient of consecutive AbsoluteRots to create a list of relative rots (listRotations)
  • splice listTranslation and listRotation back together.

Of course, there's a bit of room for doing things sequentially instead of all at once to save memory, but that's the general idea.

Edited by Quistess Alpha
  • Like 1
  • Thanks 2
Link to comment
Share on other sites

Apparently I'm a bit more industrious than I previously claimed:

rotation YPR2Rot(vector v) // Yaw Pitch Roll
{
   return
        <llSin(v.z*0.5),0,0,llCos(v.z*0.5)> *
        <0,llSin(v.y*0.5),0,llCos(v.y*0.5)> *
        <0,0,llSin(v.x*0.5),llCos(v.x*0.5)> ;
}

rotation uVectorRoll2Rot(vector v,float r)
{
   return YPR2Rot(<llAtan2(v.y,v.x),-llAtan2(v.z,llVecMag(<v.x,v.y,0>)),r>);
}

list uTransRollTime2KFM(list TransRollTimes, rotation initial_rot)
{
   list ret;
   integer index;
   integer index_max = llGetListLength(TransRollTimes)-4; // expects the list to end with a singular translation without roll or time.

   rotation base = llGetRot(); 

   rotation curr_orientation = initial_rot;
   rotation next_orientation;
   vector   curr_translation = llList2Vector(TransRollTimes,0)*base ;
   vector   next_translation ;
   for(index=0;index<=index_max;index+=3)
   {  
      next_translation = llList2Vector(TransRollTimes,index+3)*base;
      next_orientation = uVectorRoll2Rot(
        curr_translation+next_translation, 
        llList2Float(TransRollTimes,index+1)  );
      ret += [
        curr_translation,
        next_orientation/curr_orientation,
        llList2Float(TransRollTimes,index+2)  ];

      curr_orientation = next_orientation;
      curr_translation = next_translation;
   }
   return ret;
}

default
{
    state_entry()
    {
        list lTransRollTimes= // translations are relative(difference between 2 points),
        [   // but roll is absolute roll at the end of the translation.
            <llCos(TWO_PI*( 0/16.0)) ,0,llSin(TWO_PI*( 0/16.0))>, 0,  1.0,
            <llCos(TWO_PI*( 1/16.0)) ,0,llSin(TWO_PI*( 1/16.0))>, 0,  1.0,
            <llCos(TWO_PI*( 2/16.0)) ,0,llSin(TWO_PI*( 2/16.0))>, 0,  1.0,
            <llCos(TWO_PI*( 1/16.0)) ,0,llSin(TWO_PI*( 1/16.0))>, 0,  1.0,
            <llCos(TWO_PI*( 0/16.0)) ,0,llSin(TWO_PI*( 0/16.0))>, 0,  1.0,
            <llCos(TWO_PI*(-1/16.0)) ,0,llSin(TWO_PI*(-1/16.0))>, 0,  1.0,
            <llCos(TWO_PI*(-2/16.0)) ,0,llSin(TWO_PI*(-2/16.0))>, 0,  1.0,
            <llCos(TWO_PI*(-1/16.0)) ,0,llSin(TWO_PI*(-1/16.0))>, 0,  1.0,
            <llCos(TWO_PI*( 0/16.0)) ,0,llSin(TWO_PI*( 0/16.0))>, 0,  1.0,
            <llCos(TWO_PI*( 0/16.0)) ,0,llSin(TWO_PI*( 0/16.0))> // an extra translation is needed for interpolation purposes, not used.
        ];
        //llOwnerSay(llList2CSV(lTransRollTimes));
        llSetKeyframedMotion(uTransRollTime2KFM(lTransRollTimes,llGetRot()),
            [KFM_DATA,3,KFM_MODE,KFM_FORWARD]);
    }
}

Maybe I'll add it onto the rotation thread after more debugging and fiddling with a few loop-de-loops and whatnot. . . .

A bit academic, but would it make more sense to keep the roll absolute, or have it be a relative change?

Edited by Quistess Alpha
made it work when it's not starting in the default rotation.
  • Thanks 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 837 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...