Difference between revisions of "LlCastRay Test"

From Second Life Wiki
Jump to navigation Jump to search
(Created page with "Category:Test Scripts ==Purpose== Test the functionality of the llCastRay LSL command. ==Sources== LlCastRay ==Scope== (Servers shipped sometime after May 2011) ==Tes…")
 
Line 14: Line 14:
none
none


===Test 1===
===norm and position correctness test===
 
When you place this test script inside a perfect sphere, it casts ~10,200 rays from every direction, from 1m outside the sphere edge into the center of the sphere. This script reports the following error conditions:
 
    Sim performance error (llCastRay() is disabled?)
    The ray didn't hit anything
    The ray hit a different object than the sphere
    The ray hit the sphere at wrong (>1mm error) coordinates
    The returned norm isn't the exact opposite of the ray cast direction
 
To run this test:
# Rez a sphere of decently large size
# Create the below script in it
# Touch the sphere and wait for it to complete its computations. It will report any errors in llOwnerSay() chat.
# '''Verify''' it does not report any errors.
 
<pre>
default
{
    touch_start(integer total_number)
    {
      vector my_pos=llGetPos();
      vector my_scale=llGetScale();
      float my_radius=my_scale.x/2; // assume this is a sphere
     
      float scan_radius=my_radius+1.0; // how far away to be when casting rays
     
      integer theta_resolution = 100;  // scan in 100 parts
      integer phi_resolution = 100;  // scan in 100 parts
     
      integer phi_index;
      integer theta_index;
     
      float phi;
      float theta;
      integer errors;
 
      for(phi_index = 0; phi_index <= phi_resolution; phi_index++)
      {
          for(theta_index = 0; theta_index <= theta_resolution; theta_index++)
          {
              float theta = (theta_index * PI)/theta_resolution;
              float phi = (phi_index * TWO_PI)/phi_resolution;
             
              vector ray_start=my_pos;
              ray_start.x += scan_radius * llSin(theta) * llCos(phi);
              ray_start.y += scan_radius * llSin(theta) * llSin(phi);
              ray_start.z += scan_radius * llCos(theta);
             
              list hits = llCastRay(ray_start, my_pos, [RC_MAX_HITS, 1, RC_DATA_FLAGS, RC_GET_NORMAL]);
             
              integer hit_result=llList2Integer(hits, -1); // how many objects we hit
 
              string hit_message;
              integer hit_index=0;
              if(hit_result == RCERR_SIM_PERF_LOW)
              {
                  ++errors;
                  llOwnerSay("Error: RCERR_SIM_PERF_LOW @ "+(string)(ray_start-my_pos));
              }
              else if(hit_result == 0)
              {
                  ++errors; // we should always hit ourselves
                  llOwnerSay("Error: No hits @ "+(string)(ray_start-my_pos));
              }
              else
              {
                  // hit something...
                    key hit_object=llList2Key(hits, hit_index);
                    vector hit_position=llList2Vector(hits, hit_index+1);
                    vector hit_normal=llList2Vector(hits, hit_index+2);
                    if(hit_object!=llGetKey())
                    {
                        ++errors;
                        llOwnerSay("Error: Hit wrong object ("+ (string)hit_object +") @ "+(string)(ray_start-my_pos));
                    }
                    else
                    {
                        // hit ourselves
                        vector expected_hit_pos = my_pos + my_radius * < llSin(theta) * llCos(phi),  llSin(theta) * llSin(phi), llCos(theta) >;
                        vector expected_hit_norm = llVecNorm(ray_start - my_pos);
                       
                        if(expected_hit_norm * hit_normal < 0.99)
                        {
                            ++errors;
                            llOwnerSay("Error: Unexpected norm @ "+(string)(ray_start-my_pos)+"  Expected: "+(string)expected_hit_norm + " Got: "+(string)hit_normal);
                        }6.000
                       
                        if( llVecDist(expected_hit_pos, hit_position) > 0.001 )
                        {
                            ++errors;
                            llOwnerSay("Error: Unexpected hit pos @ "+(string)(ray_start-my_pos)+"  Expected: "+(string)expected_hit_pos + " Got: "+(string)hit_position);
                        } 
                    }
                   
                    integer progress = (theta_index+1) + (phi_resolution+1)*phi_index;
                    llSetText("Completed " + (string)progress + "/" + (string)((phi_resolution+1)*(theta_resolution+1)) + "\n" + (string)errors + " errors", <1,1,1>, 1);
                }
            }
        }
             
    }
}
</pre>
 
(test for mesh)
This test also works on a 'mesh' sphere (e.g. a sphere prim with 50% hollow), although I found I had to loosen my accuracy tolerances quite a bit. For a 6m hollow sphere, the test passed when my hit-position tolerance was 15cm and the norm-direction tolerance was 0.9; much tighter values resulted in many "errors".

Revision as of 16:46, 23 May 2011


Purpose

Test the functionality of the llCastRay LSL command.

Sources

LlCastRay

Scope

(Servers shipped sometime after May 2011)

Test Plan

Setup

none

norm and position correctness test

When you place this test script inside a perfect sphere, it casts ~10,200 rays from every direction, from 1m outside the sphere edge into the center of the sphere. This script reports the following error conditions:

   Sim performance error (llCastRay() is disabled?)
   The ray didn't hit anything
   The ray hit a different object than the sphere
   The ray hit the sphere at wrong (>1mm error) coordinates
   The returned norm isn't the exact opposite of the ray cast direction

To run this test:

  1. Rez a sphere of decently large size
  2. Create the below script in it
  3. Touch the sphere and wait for it to complete its computations. It will report any errors in llOwnerSay() chat.
  4. Verify it does not report any errors.
default
{
    touch_start(integer total_number)
    {
       vector my_pos=llGetPos();
       vector my_scale=llGetScale();
       float my_radius=my_scale.x/2; // assume this is a sphere
       
       float scan_radius=my_radius+1.0; // how far away to be when casting rays
       
       integer theta_resolution = 100;  // scan in 100 parts
       integer phi_resolution = 100;  // scan in 100 parts
       
       integer phi_index;
       integer theta_index;
       
       float phi;
       float theta;
       integer errors;

       for(phi_index = 0; phi_index <= phi_resolution; phi_index++)
       {
           for(theta_index = 0; theta_index <= theta_resolution; theta_index++)
           {
               float theta = (theta_index * PI)/theta_resolution;
               float phi = (phi_index * TWO_PI)/phi_resolution;
               
               vector ray_start=my_pos;
               ray_start.x += scan_radius * llSin(theta) * llCos(phi);
               ray_start.y += scan_radius * llSin(theta) * llSin(phi);
               ray_start.z += scan_radius * llCos(theta);
               
               list hits = llCastRay(ray_start, my_pos, [RC_MAX_HITS, 1, RC_DATA_FLAGS, RC_GET_NORMAL]);
               
               integer hit_result=llList2Integer(hits, -1); // how many objects we hit

               string hit_message;
               integer hit_index=0;
               if(hit_result == RCERR_SIM_PERF_LOW)
               {
                   ++errors;
                   llOwnerSay("Error: RCERR_SIM_PERF_LOW @ "+(string)(ray_start-my_pos));
               }
               else if(hit_result == 0)
               {
                   ++errors; // we should always hit ourselves
                   llOwnerSay("Error: No hits @ "+(string)(ray_start-my_pos));
               }
               else
               {
                   // hit something...
                    key hit_object=llList2Key(hits, hit_index);
                    vector hit_position=llList2Vector(hits, hit_index+1);
                    vector hit_normal=llList2Vector(hits, hit_index+2);
                    if(hit_object!=llGetKey())
                    {
                        ++errors;
                        llOwnerSay("Error: Hit wrong object ("+ (string)hit_object +") @ "+(string)(ray_start-my_pos));
                    }
                    else
                    {
                        // hit ourselves
                        vector expected_hit_pos = my_pos + my_radius * < llSin(theta) * llCos(phi),  llSin(theta) * llSin(phi), llCos(theta) >;
                        vector expected_hit_norm = llVecNorm(ray_start - my_pos);
                        
                        if(expected_hit_norm * hit_normal < 0.99)
                        {
                            ++errors;
                            llOwnerSay("Error: Unexpected norm @ "+(string)(ray_start-my_pos)+"  Expected: "+(string)expected_hit_norm + " Got: "+(string)hit_normal);
                        }6.000
                        
                        if( llVecDist(expected_hit_pos, hit_position) > 0.001 )
                        {
                            ++errors;
                            llOwnerSay("Error: Unexpected hit pos @ "+(string)(ray_start-my_pos)+"  Expected: "+(string)expected_hit_pos + " Got: "+(string)hit_position);
                        }   
                    }
                    
                    integer progress = (theta_index+1) + (phi_resolution+1)*phi_index;
                    llSetText("Completed " + (string)progress + "/" + (string)((phi_resolution+1)*(theta_resolution+1)) + "\n" + (string)errors + " errors", <1,1,1>, 1);
                }
            }
        }
               
    }
}

(test for mesh) This test also works on a 'mesh' sphere (e.g. a sphere prim with 50% hollow), although I found I had to loosen my accuracy tolerances quite a bit. For a 6m hollow sphere, the test passed when my hit-position tolerance was 15cm and the norm-direction tolerance was 0.9; much tighter values resulted in many "errors".