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

From Second Life Wiki
Jump to navigation Jump to search
 
(19 intermediate revisions by the same user not shown)
Line 9: Line 9:


=====Tests=====
=====Tests=====
First the rotation solutions were compared and they didn't compare at all.
First the rotations provided by functions 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.
: Testing rotations is a bad idea since there is no single solution to the question, but an infinite number of solutions.
All 4 functions provide valid, but different solutions.
: All 4 functions provide valid, but different rotations.
So the sensible thing to do is to test how the solution affects a vector:
So the sensible thing to do is to test how the solution rotates a vector:


== Test with random, normalized vectors ==
== Test with random, normalized vectors ==


<lsl>
<source lang="lsl2">
cycles = 0;
cycles = 0;
record = [];
record = [];
Line 25: Line 25:
     solution = rotbetween( u, v);
     solution = rotbetween( u, v);
     if ( llVecDist( u*solution, v) > epsilon ) record += [cycles, u, v];
     if ( llVecDist( u*solution, v) > epsilon ) record += [cycles, u, v];
}</lsl>
}</source>
====Results for function 1. llRotBetween====
<table style="width: 800px;" border="1" cellpadding="2"
;Errors > 1E-7 / number of test cycles
cellspacing="2">
: 10/13, 10/14
    <tr>
;Errors > 1E-6 / number of test cycles
      <th style="text-align: center;" colspan="1"
: 7/1000, 3/1000, 8/1000
rowspan="2">Errors / test cycles</th>
====Results for function 2. RotBetween====
      <th style="text-align: center;">Function 1</th>
;Errors > 1E-7 / number of test cycles
      <th style="text-align: center;">Function 2</th>
: 10/18, 10/21, 10/27
      <th style="text-align: center;">Function 3</th>
;Errors > 1E-6 / number of test cycles
      <th style="text-align: center;">Function 4</th>
: 0/1000, 0/10000
    </tr>
====Results for function 3. rotV2V====
    <tr>
;Errors > 1E-7 / number of test cycles
      <th style="text-align: center;">llRotBetween</th>
: 10/15, 10/22, 10/14
      <th style="text-align: center;">RotBetween</th>
;Errors > 1E-6 / number of test cycles
      <th style="text-align: center;">rotV2V</th>
: 0/1000, 1/10000, 0/10000
      <th style="text-align: center;">rotbetween</th>
====Results for function 4. rotbetween====
    </tr>
;Errors > 1E-7 / number of test cycles
    <tr>
: 10/16, 10/23, 10/13
      <th style="text-align: center;" colspan="1"
;Errors > 1E-6 / number of test cycles
rowspan="3">abs error &gt; 1e-7</th>
: 0/1000, 0/10000
      <td style="text-align: right;"> 10 / 13</td>
      <td style="text-align: right;"> 10 / 18</td>
      <td style="text-align: right;"> 10 / 15</td>
      <td style="text-align: right;"> 10 / 16</td>
    </tr>
    <tr>
      <td style="text-align: right;"> 10 / 14</td>
      <td style="text-align: right;"> 10 / 21</td>
      <td style="text-align: right;"> 10 / 22</td>
      <td style="text-align: right;"> 10 / 23</td>
    </tr>
    <tr>
      <td style="text-align: right;"></td>
      <td style="text-align: right;"> 10 / 27</td>
      <td style="text-align: right;">10 / 14</td>
      <td style="text-align: right;"> 10 / 13</td>
    </tr>
    <tr>
      <th style="text-align: center;" colspan="1"
rowspan="3">abs error &gt; 1e-6</th>
      <td style="text-align: right;"> 7 / 1000</td>
      <td style="text-align: right;"> 0 / 1000</td>
      <td style="text-align: right;"> 0 / 1000</td>
      <td style="text-align: right;"> 0 / 1000</td>
    </tr>
    <tr>
      <td style="text-align: right;"> 3 / 1000</td>
      <td style="text-align: right;"> 0 / 10000</td>
      <td style="text-align: right;"> 1 / 10000</td>
      <td style="text-align: right;"> 0 / 10000</td>
    </tr>
    <tr>
      <td style="text-align: right;"> 8 / 1000</td>
      <td style="text-align: right;"></td>
      <td style="text-align: right;"> 0 / 10000</td>
      <td style="text-align: right;"></td>
    </tr>
</table>


== Test with close to parallel and anti parallel vectors ==
== Test with close to parallel and anti parallel vectors ==
<lsl>
<source lang="lsl2">
cycles = 0;
cycles = 0;
record = [];
record = [];
Line 59: Line 96:
     solution = rotbetween( u, v);
     solution = rotbetween( u, v);
     if ( llVecDist( u*solution, v) > epsilon ) record += [cycles, u, v];
     if ( llVecDist( u*solution, v) > epsilon ) record += [cycles, u, v];
}</lsl>
}</source>
====Results for function 1. llRotBetween====
<table style="width: 800px;" border="1" cellpadding="2"
;Errors > 1E-3 / number of test cycles
cellspacing="2">
: 10/16, 10/15, 10/27
    <tr>
;Errors > 1E-2 / number of test cycles
      <th style="text-align: center;" colspan="1"
: 0/1000, 0/10000
rowspan="2">Errors / test cycles</th>
====Results for function 2. RotBetween====
      <th style="text-align: center;">Function 1</th>
;Errors > 1E-3 / number of test cycles
      <th style="text-align: center;">Function 2</th>
: 10/98, 10/96, 10/109
      <th style="text-align: center;">Function 3</th>
;Errors > 1E-2 / number of test cycles
      <th style="text-align: center;">Function 4</th>
: 0/1000, 0/10000
    </tr>
====Results for function 3. rotV2V====
    <tr>
;Errors > 1E-3 / number of test cycles
      <th style="text-align: center;">llRotBetween</th>
: 10/222, 10/89, 10/99
      <th style="text-align: center;">RotBetween</th>
;Errors > 1E-2 / number of test cycles
      <th style="text-align: center;">rotV2V</th>
: 0/1000, 0/10000
      <th style="text-align: center;">rotbetween</th>
====Results for function 4. rotbetween====
    </tr>
;Errors > 1E-3 / number of test cycles
    <tr>
: 10/192, 10/164, 10/75
      <th style="text-align: center;" colspan="1"
;Errors > 1E-2 / number of test cycles
rowspan="3">abs error &gt; 1e-3</th>
: 0/1000, 0/10000
      <td style="text-align: right;"> 10 / 16</td>
      <td style="text-align: right;"> 10 / 98</td>
      <td style="text-align: right;"> 10 / 222</td>
      <td style="text-align: right;"> 10 / 192</td>
    </tr>
    <tr>
      <td style="text-align: right;"> 10 / 15</td>
      <td style="text-align: right;"> 10 / 96</td>
      <td style="text-align: right;"> 10 / 89</td>
      <td style="text-align: right;"> 10 / 164</td>
    </tr>
    <tr>
      <td style="text-align: right;"> 10 / 27</td>
      <td style="text-align: right;"> 10 / 109</td>
      <td style="text-align: right;">10 / 99</td>
      <td style="text-align: right;"> 10 / 75</td>
    </tr>
    <tr>
      <th style="text-align: center;" colspan="1"
rowspan="2">abs error &gt; 1e-2</th>
      <td style="text-align: right;"> 0 / 1000</td>
      <td style="text-align: right;"> 0 / 1000</td>
      <td style="text-align: right;"> 0 / 1000</td>
      <td style="text-align: right;"> 0 / 1000</td>
    </tr>
    <tr>
      <td style="text-align: right;"> 0 / 10000</td>
      <td style="text-align: right;"> 0 / 10000</td>
      <td style="text-align: right;"> 0 / 10000</td>
      <td style="text-align: right;"> 0 / 10000</td>
    </tr>
</table>


== Conclusion ==
== Conclusion ==
Functions 2, 3 and 4 have similar performances.
Functions 2, 3 and 4 have similar performances.
Function 1, the built-in, has a lower performance
Function 1, the built-in, has a lower performance.<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 will point a vector in the right direction, i.e. the rotation's ''forward'' is the vector direction.
: See [[User:Dora_Gustafson/llRotBetween_alternatives#About_the_function.27s_nature|note]] about the functions nature
: Function 4 is different, the solution will map a rotation with ''left'' in the horizontal plane


== Scripts and functions ==
== Scripts and functions ==
;Function 1, llRotBetween()
;Function 1, llRotBetween( vector a, vector b)
: This is the built in function, see [https://wiki.secondlife.com/wiki/LlRotBetween llRotBetween]
: This is the built in function, see [[LlRotBetween|llRotBetween]]
;Function 2, RotBetween()
: See [[User:Dora_Gustafson/llRotBetween_alternatives#About_the_function.27s_nature|note]] about the functions nature
: This is the suggested [https://wiki.secondlife.com/wiki/LlRotBetween#Replacement replacement] for llRotBetween
;Function 2, RotBetween( vector a, vector b)
;Function 3, rotV2V()
: This is the suggested [[LlRotBetween#Replacement|Replacement]] for llRotBetween
<lsl>rotation rotV2V( vector a, vector b)
: See [[User:Dora_Gustafson/llRotBetween_alternatives#About_the_function.27s_nature|note]] about the functions nature
;Function 3, rotV2V( vector a, vector b)
<source lang="lsl2">rotation rotV2V( vector a, vector b)
{
{
     a = llVecNorm(a);
     a = llVecNorm(a);
Line 100: Line 175:
     return ZERO_ROTATION/llAxes2Rot( a, c, a%c)*llAxes2Rot( b, c, b%c);
     return ZERO_ROTATION/llAxes2Rot( a, c, a%c)*llAxes2Rot( b, c, b%c);
}
}
</lsl>
</source>
;Function 4, rotbetween()
: See [[User:Dora_Gustafson/llRotBetween_alternatives#About_the_function.27s_nature|note]] about the functions nature
<lsl>rotation Vec2Rot( vector a)
 
;Function 4, rotbetween( vector a, vector b)
<source lang="lsl2">rotation Vec2Rot( vector a)
{
{
     a = llVecNorm(a);
     a = llVecNorm(a);
Line 115: Line 192:
     return ZERO_ROTATION/Vec2Rot(a)*Vec2Rot(b);
     return ZERO_ROTATION/Vec2Rot(a)*Vec2Rot(b);
}
}
</lsl>
</source>
: Returns a solution that will map a rotation with ''left'' in the horizontal plane. This is convenient for cameras and prims you don't want tilted
----
 
==About the function's nature==
The function determines a rotation (quaternion) which can map a vector onto another.
: It does nothing else, which means that there are no conditions on the other vectors associated with a rotation in space.
When the solution is used to rotate a body in space one should be aware of it’s nature.
: For a prim whose rotation is defined by three orthogonal vectors the forward vector mapping will be correct while the other vector mappings are unpredictable.
: A prim mapping will normally be rotated about the prim’s forward axis in an unpredictable way.
: The prim will be tilted to one side or the other side with respect to the vertical.
There are numerous solutions to the task of finding the rotation between two vectors and all are correct in the sense that they can correctly map one vector onto another.
{{LSLC|Library}}
{{LSLC|Library}}

Latest revision as of 12:46, 22 January 2015

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 rotations provided by functions were compared and they didn't compare at all.

Testing rotations is a bad idea since there is no single solution to the question, but an infinite number of solutions.
All 4 functions provide valid, but different rotations.

So the sensible thing to do is to test how the solution rotates a vector:

Test with random, normalized vectors

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];
}
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

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];
}
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.
See note about the functions nature
Function 4 is different, the solution will map 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
See note about the functions nature
Function 2, RotBetween( vector a, vector b)
This is the suggested Replacement for llRotBetween
See note about the functions nature
Function 3, rotV2V( vector a, vector b)
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);
}
See note about the functions nature
Function 4, rotbetween( vector a, vector b)
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);
}
Returns a solution that will map a rotation with left in the horizontal plane. This is convenient for cameras and prims you don't want tilted

About the function's nature

The function determines a rotation (quaternion) which can map a vector onto another.

It does nothing else, which means that there are no conditions on the other vectors associated with a rotation in space.

When the solution is used to rotate a body in space one should be aware of it’s nature.

For a prim whose rotation is defined by three orthogonal vectors the forward vector mapping will be correct while the other vector mappings are unpredictable.
A prim mapping will normally be rotated about the prim’s forward axis in an unpredictable way.
The prim will be tilted to one side or the other side with respect to the vertical.

There are numerous solutions to the task of finding the rotation between two vectors and all are correct in the sense that they can correctly map one vector onto another.