Difference between revisions of "User:Dora Gustafson/llRotBetween alternatives"

From Second Life Wiki
Jump to navigation Jump to search
Line 154: Line 154:
All four functions are very good except with parallel and anti parallel vectors.<br>
All four functions are very good except with parallel and anti parallel vectors.<br>
The rotation found is not always what you expect.<br>
The rotation found is not always what you expect.<br>
: The rotation will point a vector in the right direction, i.e. the rotation's ''forward'' is all right.
: The rotation will point a vector in the right direction, i.e. the rotation's ''forward'' is the vector direction.
: The rotations ''left'' direction is in the plane given by the two vectors, which is not always what you want or expect
: The rotations ''left'' direction is in the plane given by the two vectors, which is not always what you want or expect
: Function 4 is different, it returns a rotation with ''left'' in the horizontal plane
: Function 4 is different, it returns a rotation with ''left'' in the horizontal plane

Revision as of 15:50, 26 December 2012

llRotBetween, some alternatives and considerations

Scope

Four functions are covered, They are

  1. llRotBetween( vector a, vector b); // The built in function
  2. RotBetween( vector a, vector b); // The replacement outlined in the wiki
  3. rotV2V( vector a, vector b); // The shortest replacement
  4. rotbetween( vector a, vector b); // Using a Vector to rotation function
Tests

First the rotation solutions were compared and they didn't compare at all. Testing rotations is a bad idea since there are no single solutions, but infinite numbers of solutions. All 4 functions provide valid, but different solutions. So the sensible thing to do is to test how the solution rotates a vector:

Test with random, normalized vectors

<lsl> cycles = 0; record = []; while ( cycles++ < nLimit && llGetListLength( record) < 30) {

   u = llVecNorm(< llFrand( 2.0)-1.0, llFrand( 2.0)-1.0, llFrand( 2.0)-1.0 >);
   v = llVecNorm(< llFrand( 2.0)-1.0, llFrand( 2.0)-1.0, llFrand( 2.0)-1.0 >);
   solution = rotbetween( u, v);
   if ( llVecDist( u*solution, v) > epsilon ) record += [cycles, u, v];

}</lsl>

Errors / test cycles Function 1 Function 2 Function 3 Function 4
llRotBetween RotBetween rotV2V rotbetween
abs error > 1e-7 10 / 13 10 / 18 10 / 15 10 / 16
10 / 14 10 / 21 10 / 22 10 / 23
10 / 27 10 / 14 10 / 13
abs error > 1e-6 7 / 1000 0 / 1000 0 / 1000 0 / 1000
3 / 1000 0 / 10000 1 / 10000 0 / 10000
8 / 1000 0 / 10000

Test with close to parallel and anti parallel vectors

<lsl> cycles = 0; record = []; while ( cycles++ < nLimit && llGetListLength( record) < 30) {

   u = llVecNorm(< llFrand( 2.0)-1.0, llFrand( 2.0)-1.0, llFrand( 2.0)-1.0 >);
   v = < llFrand( 2E-3)-1E-3, llFrand( 2E-3)-1E-3, llFrand( 2E-3)-1E-3 >;
   if ( llFrand(1.0) < 0.5 ) v -= u;
   else v += u;
   solution = rotbetween( u, v);
   if ( llVecDist( u*solution, v) > epsilon ) record += [cycles, u, v];

}</lsl>

Errors / test cycles Function 1 Function 2 Function 3 Function 4
llRotBetween RotBetween rotV2V rotbetween
abs error > 1e-3 10 / 16 10 / 98 10 / 222 10 / 192
10 / 15 10 / 96 10 / 89 10 / 164
10 / 27 10 / 109 10 / 99 10 / 75
abs error > 1e-2 0 / 1000 0 / 1000 0 / 1000 0 / 1000
0 / 10000 0 / 10000 0 / 10000 0 / 10000

Conclusion

Functions 2, 3 and 4 have similar performances. Function 1, the built-in, has a lower performance.
All four functions are very good except with parallel and anti parallel vectors.
The rotation found is not always what you expect.

The rotation will point a vector in the right direction, i.e. the rotation's forward is the vector direction.
The rotations left direction is in the plane given by the two vectors, which is not always what you want or expect
Function 4 is different, it returns a rotation with left in the horizontal plane

Scripts and functions

Function 1, llRotBetween( vector a, vector b)
This is the built in function, see llRotBetween
Returns a rotation with left in the plane given by a and b, when such a plane can be found
Function 2, RotBetween( vector a, vector b)
This is the suggested replacement for llRotBetween
Returns a rotation with left in the plane given by a and b, when such a plane can be found
Function 3, rotV2V( vector a, vector b)

<lsl>rotation rotV2V( vector a, vector b) {

   a = llVecNorm(a);
   b = llVecNorm(b);
   vector c = b;
   while ( llFabs(a*c) > 0.999999 ) c = llVecNorm(< llFrand( 2.0)-1.0, llFrand( 2.0)-1.0, llFrand( 2.0)-1.0 >);
   c = llVecNorm(a%c);
   return ZERO_ROTATION/llAxes2Rot( a, c, a%c)*llAxes2Rot( b, c, b%c);

} </lsl>

Returns a rotation with left in the plane given by a and b, when such a plane can be found
Function 4, rotbetween( vector a, vector b)

<lsl>rotation Vec2Rot( vector a) {

   a = llVecNorm(a);
   vector  c = < 0.0, 0.0, 1.0 >;
   if ( llFabs(a*c) > 0.999999 ) c = llVecNorm(< llFrand( 2.0)-1.0, llFrand( 2.0)-1.0, 0.0 >);
   vector b = llVecNorm(c%a);
   return llAxes2Rot( a, b, a%b);

}

rotation rotbetween( vector a, vector b) {

   return ZERO_ROTATION/Vec2Rot(a)*Vec2Rot(b);

} </lsl>

Returns a rotation with left in the horizontal plane. This is convenient for cameras and prims you don't want to be tilted