Innula Zenovka Posted January 10, 2022 Share Posted January 10, 2022 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)? 1 Link to comment Share on other sites More sharing options...
Wulfie Reanimator Posted January 10, 2022 Share Posted January 10, 2022 I would assume it stands for the angle in Radians, considering the name/context of the function. Link to comment Share on other sites More sharing options...
Innula Zenovka Posted January 10, 2022 Author Share Posted January 10, 2022 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. Link to comment Share on other sites More sharing options...
Wulfie Reanimator Posted January 10, 2022 Share Posted January 10, 2022 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); } } } 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. 1 1 Link to comment Share on other sites More sharing options...
Quistess Alpha Posted January 10, 2022 Share Posted January 10, 2022 (edited) 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. (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: 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 January 10, 2022 by Quistess Alpha 1 2 Link to comment Share on other sites More sharing options...
Quistess Alpha Posted January 10, 2022 Share Posted January 10, 2022 (edited) 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 January 10, 2022 by Quistess Alpha made it work when it's not starting in the default rotation. 1 Link to comment Share on other sites More sharing options...
Innula Zenovka Posted January 11, 2022 Author Share Posted January 11, 2022 Thanks so much, Wulfie and Quistess. I'll study the examples tomorrow, when I'm not tired, and I'm sure I'll have lots of questions then. 2 Link to comment Share on other sites More sharing options...
Recommended Posts
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