mass_properties_tut.cpp

Go to the documentation of this file.
00001 
00024 #include "linden_common.h"
00025 #include "lltut.h"
00026 #include <llmath/v3math.h>
00027 #include <llmath/llquaternion.h>
00028 #include <llphysics/abstract/utils/llinertiatensorutils.h>
00029 #include <llphysics/abstract/utils/llobjectmassproperties.h>
00030 #include <llphysics/abstract/utils/llprimmassproperties.h>
00031 #include <llphysics/abstract/utils/llphysicsvolumemanager.h>
00032 #include <llprimitive/llmaterialtable.h>
00033 #include <llprimitive/llprimitive.h>
00034 
00035 
00036 const F32 SMALL_RELATIVE_ERROR = 0.001f;        // 0.1%
00037 const F32 SQRT_THREE = 1.732050808f;
00038 const F32 SQRT_SIX = 2.449489743f;
00039 
00040 namespace tut
00041 {
00042         struct mass_properties_data
00043         {
00044                 LLPrimMassProperties prim_properties;
00045                 LLObjectMassProperties object_properties;
00046         };
00047 
00048         typedef test_group<mass_properties_data> mass_properties_group;
00049         typedef mass_properties_group::object mass_properties;
00050         tut::mass_properties_group mp_test_group("mass properties");
00051 
00052         template<> template<>
00053         void mass_properties::test<1>()
00054         {
00055                 // test SPHERE mass properties
00056                 LLPrimMassProperties prim_sphere;
00057                 prim_sphere.setUnitSphere();
00058 
00059                 F32 density = 1000.f;
00060                 F32 radius = 5.f;
00061                 F32 diameter = 2.f * radius;
00062                 LLVector3 scale(diameter, diameter, diameter);
00063                 LLObjectMassProperties obj_sphere(prim_sphere, scale, density);
00064                 
00065                 F32 computed_mass = obj_sphere.getMass();
00066                 //LLVector3 center_of_mass
00067                 //obj_sphere.getCenterOfMass(center_of_mass);
00068                 LLMatrix3 inertia;
00069                 obj_sphere.getInertiaLocal(inertia);
00070                 F32 computed_inertia_eigenvalue = inertia.mMatrix[0][0];
00071 
00072 
00073                 // volume is normalized for scale = <1,1,1>
00074                 // V = 4/3 * PI * r^3
00075                 // inertia_eigenvalue = (2/5) * M * r^2
00076                 F32 volume = ( 4.f / 3.f ) * radius * radius * radius * F_PI;
00077                 F32 expected_mass = density * volume;
00078                 F32 expected_inertia_eigenvalue = ( 2.f / 5.f ) * expected_mass * radius * radius;
00079         
00080                 F32 error = fabs(computed_mass - expected_mass) / expected_mass;
00081                 ensure("expected sphere mass should match computed", error < SMALL_RELATIVE_ERROR);
00082 
00083                 error = fabs(computed_inertia_eigenvalue - expected_inertia_eigenvalue) / expected_inertia_eigenvalue;
00084                 ensure("expected sphere inertia should match computed", error < SMALL_RELATIVE_ERROR);
00085         }
00086 
00087         template<> template<>
00088         void mass_properties::test<2>()
00089         {
00090                 // test LLInertiaTensorUtils
00091 
00092                 // define a known inertia tensor in the center of mass frame
00093                 // from the numerical example in this paper:
00094                 // http://www.journaldatabase.org/articles/87064/Explicit_Exact_Formulas_f.html
00095                 F32 known_mass = 1873.23f;
00096                 LLVector3 known_center( 0.f, 0.f, 0.f );
00097                 LLMatrix3 known_inertia;
00098                 known_inertia.mMatrix[0][0] = 43520.33257f;
00099                 known_inertia.mMatrix[1][1] = 194711.28938f;
00100                 known_inertia.mMatrix[2][2] = 191168.76173f;
00101 
00102                 known_inertia.mMatrix[0][1] = -11996.20119f;
00103                 known_inertia.mMatrix[1][0] = -11996.20119f;
00104 
00105                 known_inertia.mMatrix[0][2] =  46343.16662f;
00106                 known_inertia.mMatrix[2][0] =  46343.16662f;
00107 
00108                 known_inertia.mMatrix[2][1] = -4417.66150f;
00109                 known_inertia.mMatrix[1][2] = -4417.66150f;
00110 
00111                 // the following two shifts should have null effect
00112                 {
00113                         LLVector3 first_shift(2.f, 3.f, 4.f);
00114                         LLVector3 second_shift = - first_shift;
00115                         LLMatrix3 inertia = known_inertia;
00116                         
00117                         LLInertiaTensorUtils::shiftCenteredInertiaTensor(inertia, first_shift, known_mass);
00118                         LLInertiaTensorUtils::centerInertiaTensor(inertia, second_shift, known_mass);
00119 
00120                         // we should now have the same inertia with which we started
00121                         for (S32 i=0; i<3; ++i)
00122                         {
00123                                 for (S32 j=0; j<3; ++j)
00124                                 {
00125                                         F32 error = fabs(1.f - inertia.mMatrix[i][j] / known_inertia.mMatrix[i][j]);
00126                                         ensure("LLInertiaTensorUtils shift+sclae-shift-scale should be no-op", error < SMALL_RELATIVE_ERROR);
00127                                 }
00128                         }
00129                 }
00130 
00131                 // the following series operations should have null effect
00132                 {
00133                         LLVector3 first_shift(1.f, 5.f, 10.f);
00134                         LLVector3 second_scale(2.f, 3.f, 4.f);
00135                         LLVector3 third_shift;
00136                         LLVector3 fourth_scale;
00137                         for (S32 i = 0; i < 3; ++i)
00138                         {
00139                                 third_shift.mV[i] = -first_shift.mV[i] * second_scale.mV[i];
00140                                 fourth_scale.mV[i] = 1.f / second_scale.mV[i];
00141                         }
00142         
00143                         F32 mass = known_mass;
00144                         LLVector3 center = known_center;
00145                         LLMatrix3 inertia = known_inertia;
00146         
00147                         // first
00148                         LLInertiaTensorUtils::shiftCenteredInertiaTensor(inertia, first_shift, mass);
00149                         center += first_shift;
00150         
00151                         // second
00152                         LLInertiaTensorUtils::scaleInertiaTensor(inertia, second_scale);
00153                         mass *= second_scale.mV[VX] * second_scale.mV[VY] * second_scale.mV[VZ];
00154                         for (S32 i = 0; i < 3; ++i)
00155                         {
00156                                 center.mV[i] *= second_scale.mV[i];
00157                         }
00158         
00159                         // third
00160                         LLInertiaTensorUtils::centerInertiaTensor(inertia, third_shift, mass);
00161                         center -= third_shift;
00162         
00163                         // foruth
00164                         LLInertiaTensorUtils::scaleInertiaTensor(inertia, fourth_scale);
00165         
00166                         // we should now have the same inertia with which we started
00167                         for (S32 i=0; i<3; ++i)
00168                         {
00169                                 for (S32 j=0; j<3; ++j)
00170                                 {
00171                                         F32 error = fabs(1.f - inertia.mMatrix[i][j] / known_inertia.mMatrix[i][j]);
00172                                         ensure("LLInertiaTensorUtils shift+sclae-shift-scale should be no-op", error < SMALL_RELATIVE_ERROR);
00173                                 }
00174                         }
00175                 }
00176         }
00177 
00178         template<> template<>
00179         void mass_properties::test<3>()
00180         {
00181                 // test tetrahedral decomposition of unit tetrahedron centered on origin
00182                 std::vector< LLVector3 > points;
00183                 points.push_back( LLVector3(  0.f, 0.f, 0.f ) );
00184                 points.push_back( LLVector3(  1.f, 0.f, 0.f ) );
00185                 points.push_back( LLVector3( 0.5f, 0.5f * SQRT_THREE, 0.f) );
00186                 points.push_back( LLVector3( 0.5f, SQRT_THREE / 6.f, SQRT_SIX / 3.f) );
00187 
00188                 // compute the center
00189                 LLVector3 center;
00190                 for (S32 i = 0; i < (S32)points.size(); ++i)
00191                 {
00192                         center += points[i];
00193                 }
00194                 center *= ( 1.f / F32(points.size()) );
00195 
00196                 // shift all points to center of mass frame
00197                 for (S32 i = 0; i < (S32)points.size(); ++i)
00198                 {
00199                         points[i] -= center;
00200                 }
00201 
00202                 LLPrimMassProperties tetrahedron;
00203                 tetrahedron.addSignedTetrahedron(1.0, points[0], points[1], points[2], points[3]);
00204                 // we must manually center the inertia tensor here 
00205                 // since addSignedTetrahedron() does not do it automatically
00206                 tetrahedron.centerInertiaTensor();
00207 
00208                 F32 density = 1.0f;
00209                 LLVector3 scale(1.f, 1.f, 1.f);
00210                 LLMatrix3 analytic_inertia;
00211                 tetrahedron.getScaledInertiaTensor(analytic_inertia, scale, density);
00212 
00213                 // compute the mesh
00214                 std::vector< S32 > triangle_indices;
00215                 triangle_indices.push_back(0);
00216                 triangle_indices.push_back(2);
00217                 triangle_indices.push_back(1);
00218 
00219                 triangle_indices.push_back(0);
00220                 triangle_indices.push_back(1);
00221                 triangle_indices.push_back(3);
00222 
00223                 triangle_indices.push_back(0);
00224                 triangle_indices.push_back(3);
00225                 triangle_indices.push_back(2);
00226 
00227                 triangle_indices.push_back(1);
00228                 triangle_indices.push_back(2);
00229                 triangle_indices.push_back(3);
00230 
00231                 // compute the same inertia using a mesh
00232                 {
00233                         LLPrimMassProperties mesh;
00234                         mesh.setUnitMesh(points, triangle_indices);
00235 
00236                         // the two properties should agree
00237                         F32 error = ( tetrahedron.getVolume() - mesh.getVolume() ) / tetrahedron.getVolume();
00238                         ensure("tetrahedron and mesh volume should match", error < SMALL_RELATIVE_ERROR);
00239         
00240                         error = ( tetrahedron.getCenterOfMass() - mesh.getCenterOfMass() ).length();
00241                         ensure("tetrahedron and mesh centers should match", error < SMALL_RELATIVE_ERROR);
00242         
00243                         LLMatrix3 mesh_inertia;
00244                         mesh.getScaledInertiaTensor(mesh_inertia, scale, density);
00245 
00246                         for (S32 i=0; i<3; ++i)
00247                         {
00248                                 for (S32 j=0; j<3; ++j)
00249                                 {
00250                                         // only verify the non-small elements
00251                                         if (analytic_inertia.mMatrix[i][j] > SMALL_RELATIVE_ERROR)
00252                                         {
00253                                                 error = fabs(1.f - mesh_inertia.mMatrix[i][j] / analytic_inertia.mMatrix[i][j]);
00254                                                 ensure("LLPrimMassProperties::setUnitMesh() inertia ", error < SMALL_RELATIVE_ERROR);
00255                                         }
00256                                 }
00257                         }
00258                 }
00259 
00260                 // shift the whole tetrahedron away from the center of mass and recompute the mesh
00261                 {
00262                         LLVector3 shift(11.f, 7.f, 3.f);
00263                         for (S32 i = 0; i < (S32)points.size(); ++i)
00264                         {
00265                                 points[i] += shift;
00266                         }
00267                         LLPrimMassProperties mesh;
00268                         mesh.setUnitMesh(points, triangle_indices);
00269         
00270                         // the two properties should agree
00271                         F32 error = ( tetrahedron.getVolume() - mesh.getVolume() ) / tetrahedron.getVolume();
00272                         ensure("tetrahedron and mesh volume should match", error < SMALL_RELATIVE_ERROR);
00273         
00274                         LLMatrix3 mesh_inertia;
00275                         mesh.getScaledInertiaTensor(mesh_inertia, scale, density);
00276 
00277                         for (S32 i=0; i<3; ++i)
00278                         {
00279                                 for (S32 j=0; j<3; ++j)
00280                                 {
00281                                         // only verify the non-small elements
00282                                         if (analytic_inertia.mMatrix[i][j] > SMALL_RELATIVE_ERROR)
00283                                         {
00284                                                 error = fabs(1.f - mesh_inertia.mMatrix[i][j] / analytic_inertia.mMatrix[i][j]);
00285                                                 ensure("LLPrimMassProperties::setUnitMesh() inertia ", error < SMALL_RELATIVE_ERROR);
00286                                         }
00287                                 }
00288                         }
00289                 }
00290         }
00291 
00292         template<> template<>
00293         void mass_properties::test<4>()
00294         {
00295                 // test tetrahedron utilities
00296 
00297                 // from the paper described here:
00298                 // from the numerical example in this paper:
00299                 // http://www.journaldatabase.org/articles/87064/Explicit_Exact_Formulas_f.html
00300 
00301                 // initialize info about the tetrahedron
00302                 std::vector< LLVector3 > points;
00303                 points.push_back( LLVector3(  8.33220f, -11.86875f,   0.93355f) );
00304                 points.push_back( LLVector3(  0.75523f,   5.00000f,  16.37072f) );
00305                 points.push_back( LLVector3( 52.61236f,   5.00000f, - 5.38580f) );
00306                 points.push_back( LLVector3(  2.00000f,   5.00000f,   3.00000f) );
00307 
00308                 LLVector3 expected_center( 15.92492f, 0.78281f, 3.732962f);
00309 
00310                 LLMatrix3 expected_inertia;
00311                 expected_inertia.mMatrix[0][0] = 43520.33257f;
00312                 expected_inertia.mMatrix[1][1] = 194711.28938f;
00313                 expected_inertia.mMatrix[2][2] = 191168.76173f;
00314 
00315                 expected_inertia.mMatrix[0][1] = -11996.20119f;
00316                 expected_inertia.mMatrix[1][0] = -11996.20119f;
00317 
00318                 expected_inertia.mMatrix[0][2] =  46343.16662f;
00319                 expected_inertia.mMatrix[2][0] =  46343.16662f;
00320 
00321                 expected_inertia.mMatrix[2][1] = -4417.66150f;
00322                 expected_inertia.mMatrix[1][2] = -4417.66150f;
00323 
00324                 // measure tetrahedron bounding box max dimension 
00325                 // for relative error estimates
00326                 LLVector3 box_min(FLT_MAX, FLT_MAX, FLT_MAX);
00327                 LLVector3 box_max(-FLT_MAX, -FLT_MAX, -FLT_MAX);
00328                 for (S32 point_index = 0; point_index < (S32)points.size(); ++point_index)
00329                 {
00330                         for (S32 i = 0; i < 3; ++i)
00331                         {
00332                                 if (points[point_index].mV[i] < box_min.mV[i])
00333                                 {
00334                                         box_min.mV[i] = points[point_index].mV[i];
00335                                 }
00336                                 if (points[point_index].mV[i] > box_max.mV[i])
00337                                 {
00338                                         box_max.mV[i] = points[point_index].mV[i];
00339                                 }
00340                         }
00341                 }
00342                 F32 tetrahedron_max_dimension = (box_max - box_min).length();
00343 
00344 
00345                 // test LLPrimMassProperties::addSignedTetrahedron()
00346                 {
00347                         LLPrimMassProperties tetrahedron;
00348                         tetrahedron.addSignedTetrahedron(1.f, points[0], points[1], points[2], points[3]);
00349                         // we must manually center the inertia tensor here 
00350                         // since addSignedTetrahedron() does not do it automatically
00351                         tetrahedron.centerInertiaTensor();
00352         
00353                         // check the center of mass
00354                         LLVector3 center = tetrahedron.getCenterOfMass();
00355                         F32 error = (center - expected_center).length() / tetrahedron_max_dimension;
00356         
00357                         ensure("LLPrimMassProperties::addSignedTetrahedron() center of mass ", error < SMALL_RELATIVE_ERROR);
00358         
00359                         // check the inertia tensor
00360                         LLMatrix3 computed_inertia;
00361                         LLVector3 scale(1.f, 1.f, 1.f);
00362                         F32 density = 1.f;
00363                         tetrahedron.getScaledInertiaTensor(computed_inertia, scale, density);
00364 
00365                         for (S32 i=0; i<3; ++i)
00366                         {
00367                                 for (S32 j=0; j<3; ++j)
00368                                 {
00369                                         error = fabs(1.f - computed_inertia.mMatrix[i][j] / expected_inertia.mMatrix[i][j]);
00370                                         ensure("LLPrimMassProperties::addSignedTetrahedron inertia ", error < SMALL_RELATIVE_ERROR);
00371                                 }
00372                         }
00373                 }
00374 
00375                 // test LLPrimMassProperties::addUnitMesh()
00376                 {
00377                         std::vector< S32 > triangle_indices;
00378                         triangle_indices.push_back(0);
00379                         triangle_indices.push_back(2);
00380                         triangle_indices.push_back(1);
00381         
00382                         triangle_indices.push_back(1);
00383                         triangle_indices.push_back(3);
00384                         triangle_indices.push_back(0);
00385         
00386                         triangle_indices.push_back(2);
00387                         triangle_indices.push_back(0);
00388                         triangle_indices.push_back(3);
00389         
00390                         triangle_indices.push_back(3);
00391                         triangle_indices.push_back(1);
00392                         triangle_indices.push_back(2);
00393         
00394                         LLPrimMassProperties mesh;
00395                         mesh.setUnitMesh(points, triangle_indices);
00396 
00397                         // check the center of mass
00398                         LLVector3 center = mesh.getCenterOfMass();
00399                         F32 error = (center - expected_center).length() / tetrahedron_max_dimension;
00400         
00401                         ensure("LLPrimMassProperties::setUnitMesh() center of mass ", error < SMALL_RELATIVE_ERROR);
00402         
00403                         // check the inertia tensor
00404                         LLMatrix3 computed_inertia;
00405                         LLVector3 scale(1.f, 1.f, 1.f);
00406                         F32 density = 1.f;
00407                         mesh.getScaledInertiaTensor(computed_inertia, scale, density);
00408 
00409                         for (S32 i=0; i<3; ++i)
00410                         {
00411                                 for (S32 j=0; j<3; ++j)
00412                                 {
00413                                         error = fabs(1.f - computed_inertia.mMatrix[i][j] / expected_inertia.mMatrix[i][j]);
00414                                         ensure("LLPrimMassProperties::setUnitMesh() inertia diagonal elements mismatch", error < SMALL_RELATIVE_ERROR);
00415                                 }
00416                         }
00417                 }
00418         }
00419 
00420         template<> template<>
00421         void mass_properties::test<5>()
00422         {
00423                 // test LLPrimMassProperties
00424 
00425                 // unit shape box
00426                 LLPrimMassProperties box;
00427                 box.setUnitBox();
00428 
00429                 // unit shape mesh -- box
00430 
00431                 //      
00432                 //          4-----------0
00433                 //  z      /|          /|
00434                 //  |     / |         / |
00435                 //  |    /  |        /  |
00436                 //  |   6-----------2   |
00437                 //  |   |   |       |   |
00438                 //  |   |   5-------|---1
00439                 //  |   |  /        |  /
00440                 //  |   | /         | /
00441                 //  | y |/          |/
00442                 //  |/  7-----------3
00443                 //  +------------------------ x
00444 
00445                 std::vector< LLVector3 > points;
00446                 points.push_back( LLVector3( 0.5f,  0.5f,  0.5f) );
00447                 points.push_back( LLVector3( 0.5f,  0.5f, -0.5f) );
00448                 points.push_back( LLVector3( 0.5f, -0.5f,  0.5f) );
00449                 points.push_back( LLVector3( 0.5f, -0.5f, -0.5f) );
00450                 points.push_back( LLVector3(-0.5f,  0.5f,  0.5f) );
00451                 points.push_back( LLVector3(-0.5f,  0.5f, -0.5f) );
00452                 points.push_back( LLVector3(-0.5f, -0.5f,  0.5f) );
00453                 points.push_back( LLVector3(-0.5f, -0.5f, -0.5f) );
00454 
00455                 std::vector< S32 > triangle_indices;
00456                 // +x
00457                 triangle_indices.push_back(1);
00458                 triangle_indices.push_back(0);
00459                 triangle_indices.push_back(2);
00460 
00461                 triangle_indices.push_back(1);
00462                 triangle_indices.push_back(2);
00463                 triangle_indices.push_back(3);
00464 
00465                 // -y
00466                 triangle_indices.push_back(3);
00467                 triangle_indices.push_back(2);
00468                 triangle_indices.push_back(7);
00469 
00470                 triangle_indices.push_back(7);
00471                 triangle_indices.push_back(2);
00472                 triangle_indices.push_back(6);
00473 
00474                 // -x
00475                 triangle_indices.push_back(7);
00476                 triangle_indices.push_back(6);
00477                 triangle_indices.push_back(4);
00478 
00479                 triangle_indices.push_back(7);
00480                 triangle_indices.push_back(4);
00481                 triangle_indices.push_back(5);
00482 
00483                 // +y
00484                 triangle_indices.push_back(5);
00485                 triangle_indices.push_back(4);
00486                 triangle_indices.push_back(1);
00487 
00488                 triangle_indices.push_back(1);
00489                 triangle_indices.push_back(4);
00490                 triangle_indices.push_back(0);
00491 
00492                 // +z
00493                 triangle_indices.push_back(0);
00494                 triangle_indices.push_back(4);
00495                 triangle_indices.push_back(6);
00496 
00497                 triangle_indices.push_back(0);
00498                 triangle_indices.push_back(6);
00499                 triangle_indices.push_back(2);
00500 
00501                 // -z
00502                 triangle_indices.push_back(7);
00503                 triangle_indices.push_back(5);
00504                 triangle_indices.push_back(3);
00505 
00506                 triangle_indices.push_back(3);
00507                 triangle_indices.push_back(5);
00508                 triangle_indices.push_back(1);
00509                                 
00510                 LLPrimMassProperties mesh;
00511                 mesh.setUnitMesh(points, triangle_indices);
00512 
00513                 // the unit box and unit mesh mass properties should be nearly the same
00514 
00515                 // volume should agree
00516                 F32 error = fabs(box.getVolume() - mesh.getVolume()) / box.getVolume();
00517                 ensure("UnitBox and UnitMesh(box) should have same volume", error < SMALL_RELATIVE_ERROR);
00518 
00519                 // center of mass should agree
00520                 LLVector3 box_center = box.getCenterOfMass();
00521                 LLVector3 mesh_center = mesh.getCenterOfMass();
00522                 error = fabs( (box_center - mesh_center).length() );
00523                 ensure("UnitBox and UnitMesh(box) centers of mass should agree", error < SMALL_RELATIVE_ERROR );
00524 
00525                 LLVector3 scale(1.f, 1.f, 1.f);
00526                 F32 density = 1.f;
00527                 LLMatrix3 box_inertia, mesh_inertia;
00528                 box.getScaledInertiaTensor(box_inertia, scale, density);
00529                 mesh.getScaledInertiaTensor(mesh_inertia, scale, density);
00530 
00531                 // mesh eigenvalues should be uniform
00532                 for (S32 i = 0; i < 2; ++i)
00533                 {
00534                         error =  fabs(mesh_inertia.mMatrix[i][i] - mesh_inertia.mMatrix[i+1][i+1]) / mesh_inertia.mMatrix[i][i];
00535                         ensure("UnitMesh(box) should have uniform eigenvalues", error < SMALL_RELATIVE_ERROR);
00536                 }
00537                 // inertias should agree
00538                 for (S32 i = 0; i < 3; ++i)
00539                 {
00540                         for (S32 j = 0; j < 3; ++j)
00541                         {
00542                                 error = fabs(box_inertia.mMatrix[i][j] - mesh_inertia.mMatrix[i][j]);
00543                                 if (error > 0.f
00544                                         && box_inertia.mMatrix[i][j] != 0.f)
00545                                 {
00546                                         error /= box_inertia.mMatrix[i][j];
00547                                 }
00548                                 ensure("UnitBox and UnitMesh(box) should have same inertia", error < SMALL_RELATIVE_ERROR);
00549                         }
00550                 }
00551 
00552                 // Here we test the boundary of the LLPrimLinkInfo::canLink() method 
00553                 // between semi-random middle-sized objects.
00554         }
00555 
00556         template<> template<>
00557         void mass_properties::test<6>()
00558         {
00559                 // test LLObjectMassProperties
00560 
00561                 // we make a large single-prim box, then a similarly shaped object
00562                 // that is multiple prims, and compare their mass properties
00563 
00564                 LLPrimMassProperties box;
00565                 box.setUnitBox();
00566 
00567                 F32 density = 3.7f;
00568                 LLVector3 big_scale(1.f, 2.f, 3.f);
00569                 LLObjectMassProperties big_box(box, big_scale, density);
00570 
00571                 LLObjectMassProperties multiple_box;
00572                 LLVector3 position;
00573                 LLQuaternion rotation;
00574                 rotation.loadIdentity();
00575 
00576                 F32 small_box_size = 0.5f;
00577                 LLVector3 small_scale( small_box_size, small_box_size, small_box_size);
00578                 S32 num_boxes_x = S32(big_scale.mV[VX] / small_box_size);
00579                 S32 num_boxes_y = S32(big_scale.mV[VY] / small_box_size);
00580                 S32 num_boxes_z = S32(big_scale.mV[VZ] / small_box_size);
00581                 LLVector3 start_pos = 0.5f * (small_scale - big_scale);
00582                 for (S32 x = 0; x < num_boxes_x; ++x)
00583                 {
00584                         for (S32 y = 0; y < num_boxes_y; ++y)
00585                         {
00586                                 for (S32 z = 0; z < num_boxes_z; ++z)
00587                                 {
00588                                         position.set( F32(x) * small_box_size, F32(y) * small_box_size, F32(z) * small_box_size );
00589                                         position += start_pos;
00590 
00591                                         multiple_box.add(box, small_scale, density, position, rotation);
00592                                 }
00593                         }
00594                 }
00595 
00596                 // the mass properties of the two boxes should match
00597 
00598                 // mass
00599                 F32 big_mass = big_box.getMass();
00600                 F32 multiple_mass = multiple_box.getMass();
00601                 F32 error = (big_mass - multiple_mass) / big_mass;
00602                 ensure("Big box and equivalent multi-prim box should have same mass", error < SMALL_RELATIVE_ERROR);
00603 
00604                 // center of mass
00605                 LLVector3 big_center, multiple_center;
00606                 big_box.getCenterOfMass(big_center);
00607                 multiple_box.getCenterOfMass(multiple_center);
00608                 error = (big_center - multiple_center).length();
00609                 ensure("Big box and equivalent multi-prim box should have same center", error < SMALL_RELATIVE_ERROR);
00610 
00611                 // inertia
00612                 LLMatrix3 big_inertia, multiple_inertia;
00613                 big_box.getInertiaLocal(big_inertia);
00614                 multiple_box.getInertiaLocal(multiple_inertia);
00615                 for (S32 i = 0; i < 3; ++i)
00616                 {
00617                         for (S32 j = 0; j < 3; ++j)
00618                         {
00619                                 error = fabs(big_inertia.mMatrix[i][j] - multiple_inertia.mMatrix[i][j]);
00620                                 if (error > 0.f
00621                                         && big_inertia.mMatrix[i][j] != 0.f)
00622                                 {
00623                                         error /= big_inertia.mMatrix[i][j];
00624                                 }
00625                                 ensure("UnitBox and UnitMesh(box) should have same inertia", error < SMALL_RELATIVE_ERROR);
00626                         }
00627                 }
00628         }
00629 
00630         template<> template<>
00631         void mass_properties::test<7>()
00632         {
00633                 // test LLObjectMassProperties with rotations
00634 
00635                 // we make a large single-prim box via mesh, then a similarly shaped 
00636                 // object that is multiple prims (implicit boxes), and compare their 
00637                 // mass properties
00638 
00639                 //      
00640                 //          4-----------0
00641                 //  z      /|          /|
00642                 //  |     / |         / |
00643                 //  |    /  |        /  |
00644                 //  |   6-----------2   |
00645                 //  |   |   |       |   |
00646                 //  |   |   5-------|---1
00647                 //  |   |  /        |  /
00648                 //  |   | /         | /
00649                 //  | y |/          |/
00650                 //  |/  7-----------3
00651                 //  +------------------------ x
00652 
00653                 std::vector< LLVector3 > points;
00654                 points.push_back( LLVector3( 0.5f,  0.5f,  0.5f) );
00655                 points.push_back( LLVector3( 0.5f,  0.5f, -0.5f) );
00656                 points.push_back( LLVector3( 0.5f, -0.5f,  0.5f) );
00657                 points.push_back( LLVector3( 0.5f, -0.5f, -0.5f) );
00658                 points.push_back( LLVector3(-0.5f,  0.5f,  0.5f) );
00659                 points.push_back( LLVector3(-0.5f,  0.5f, -0.5f) );
00660                 points.push_back( LLVector3(-0.5f, -0.5f,  0.5f) );
00661                 points.push_back( LLVector3(-0.5f, -0.5f, -0.5f) );
00662 
00663                 std::vector< S32 > triangle_indices;
00664                 // +x
00665                 triangle_indices.push_back(1);
00666                 triangle_indices.push_back(0);
00667                 triangle_indices.push_back(2);
00668 
00669                 triangle_indices.push_back(1);
00670                 triangle_indices.push_back(2);
00671                 triangle_indices.push_back(3);
00672 
00673                 // -y
00674                 triangle_indices.push_back(3);
00675                 triangle_indices.push_back(2);
00676                 triangle_indices.push_back(7);
00677 
00678                 triangle_indices.push_back(7);
00679                 triangle_indices.push_back(2);
00680                 triangle_indices.push_back(6);
00681 
00682                 // -x
00683                 triangle_indices.push_back(7);
00684                 triangle_indices.push_back(6);
00685                 triangle_indices.push_back(4);
00686 
00687                 triangle_indices.push_back(7);
00688                 triangle_indices.push_back(4);
00689                 triangle_indices.push_back(5);
00690 
00691                 // +y
00692                 triangle_indices.push_back(5);
00693                 triangle_indices.push_back(4);
00694                 triangle_indices.push_back(1);
00695 
00696                 triangle_indices.push_back(1);
00697                 triangle_indices.push_back(4);
00698                 triangle_indices.push_back(0);
00699 
00700                 // +z
00701                 triangle_indices.push_back(0);
00702                 triangle_indices.push_back(4);
00703                 triangle_indices.push_back(6);
00704 
00705                 triangle_indices.push_back(0);
00706                 triangle_indices.push_back(6);
00707                 triangle_indices.push_back(2);
00708 
00709                 // -z
00710                 triangle_indices.push_back(7);
00711                 triangle_indices.push_back(5);
00712                 triangle_indices.push_back(3);
00713 
00714                 triangle_indices.push_back(3);
00715                 triangle_indices.push_back(5);
00716                 triangle_indices.push_back(1);
00717 
00718                 F32 angle_step = F_PI / (2.f * 3.f);
00719                 for (F32 angle = 0.f; angle < 0.51f * F_PI; angle += angle_step)
00720                 {
00721                         // scale and rotate mesh points
00722                         LLVector3 axis(0.f, 0.f, angle);
00723                         LLQuaternion mesh_rotation(angle, axis);
00724                         LLVector3 big_scale(3.f, 5.f, 7.f);
00725                         std::vector< LLVector3 > new_points;
00726                         for (S32 p = 0; p < (S32)points.size(); ++p)
00727                         {
00728                                 LLVector3 new_point = points[p];
00729                                 for (S32 i = 0; i < 3; ++i)
00730                                 {
00731                                         new_point.mV[i] *= big_scale.mV[i];
00732                                 }
00733                                 new_points.push_back( new_point * mesh_rotation );
00734                         }
00735                                 
00736                         // build the big mesh box
00737                         LLPrimMassProperties mesh_box;
00738                         mesh_box.setUnitMesh(new_points, triangle_indices);
00739         
00740                         F32 density = 3.7f;
00741                         LLVector3 unit_scale(1.f, 1.f, 1.f);
00742                         LLObjectMassProperties big_box(mesh_box, unit_scale, density);
00743         
00744                         // build the multiple_box
00745                         LLPrimMassProperties box;
00746                         box.setUnitBox();
00747         
00748                         LLObjectMassProperties multiple_box;
00749                         LLVector3 position;
00750         
00751                         F32 small_box_size = 0.5f;
00752                         LLVector3 small_scale( small_box_size, small_box_size, small_box_size);
00753                         S32 num_boxes_x = S32(big_scale.mV[VX] / small_box_size);
00754                         S32 num_boxes_y = S32(big_scale.mV[VY] / small_box_size);
00755                         S32 num_boxes_z = S32(big_scale.mV[VZ] / small_box_size);
00756                         LLVector3 start_pos = (0.5f * (small_scale - big_scale)) * mesh_rotation;
00757                         for (S32 x = 0; x < num_boxes_x; ++x)
00758                         {
00759                                 for (S32 y = 0; y < num_boxes_y; ++y)
00760                                 {
00761                                         for (S32 z = 0; z < num_boxes_z; ++z)
00762                                         {
00763                                                 position.set( F32(x) * small_box_size, F32(y) * small_box_size, F32(z) * small_box_size );
00764                                                 position *= mesh_rotation;
00765                                                 position += start_pos;
00766                                                 multiple_box.add(box, small_scale, density, position, mesh_rotation);
00767                                         }
00768                                 }
00769                         }
00770 
00771                         // the mass properties of the two boxes should match
00772 
00773                         // mass
00774                         F32 big_mass = big_box.getMass();
00775                         F32 multiple_mass = multiple_box.getMass();
00776                         F32 error = (big_mass - multiple_mass) / big_mass;
00777                         ensure("Big box and equivalent multi-prim box should have same mass", error < SMALL_RELATIVE_ERROR);
00778 
00779                         // center of mass
00780                         LLVector3 big_center, multiple_center;
00781                         big_box.getCenterOfMass(big_center);
00782                         multiple_box.getCenterOfMass(multiple_center);
00783                         error = (big_center - multiple_center).length();
00784                         ensure("Big box and equivalent multi-prim box should have same center", error < SMALL_RELATIVE_ERROR);
00785 
00786                         LLMatrix3 big_inertia, multiple_inertia;
00787                         big_box.getInertiaLocal(big_inertia);
00788                         multiple_box.getInertiaLocal(multiple_inertia);
00789 
00790                         for (S32 i = 0; i < 3; ++i)
00791                         {
00792                                 for (S32 j = 0; j < 3; ++j)
00793                                 {
00794                                         error = fabs(big_inertia.mMatrix[i][j] - multiple_inertia.mMatrix[i][j]);
00795                                         if (error > 0.f
00796                                                 && big_inertia.mMatrix[i][j] > SMALL_RELATIVE_ERROR)
00797                                         {
00798                                                 error /= big_inertia.mMatrix[i][j];
00799                                         }
00800                                         ensure("UnitBox and UnitMesh(box) should have same inertia", error < SMALL_RELATIVE_ERROR);
00801                                 }
00802                         }
00803                 }
00804         }
00805 
00806         template<> template<>
00807         void mass_properties::test<8>()
00808         {
00809                 // test LLPhysicsVolumeManager
00810 
00811                 // we make a large single-prim box, then a similarly shaped object
00812                 // that is multiple prims, and compare their mass properties
00813 
00814                 // first we make the single-prim giant
00815                 //      
00816                 //          4-----------0
00817                 //  z      /|          /|
00818                 //  |     / |         / |
00819                 //  |    /  |        /  |
00820                 //  |   6-----------2   |
00821                 //  |   |   |       |   |
00822                 //  |   |   5-------|---1
00823                 //  |   |  /        |  /
00824                 //  |   | /         | /
00825                 //  | y |/          |/
00826                 //  |/  7-----------3
00827                 //  +------------------------ x
00828 
00829                 std::vector< LLVector3 > points;
00830                 points.push_back( LLVector3( 0.5f,  0.5f,  0.5f) );
00831                 points.push_back( LLVector3( 0.5f,  0.5f, -0.5f) );
00832                 points.push_back( LLVector3( 0.5f, -0.5f,  0.5f) );
00833                 points.push_back( LLVector3( 0.5f, -0.5f, -0.5f) );
00834                 points.push_back( LLVector3(-0.5f,  0.5f,  0.5f) );
00835                 points.push_back( LLVector3(-0.5f,  0.5f, -0.5f) );
00836                 points.push_back( LLVector3(-0.5f, -0.5f,  0.5f) );
00837                 points.push_back( LLVector3(-0.5f, -0.5f, -0.5f) );
00838 
00839                 std::vector< S32 > triangle_indices;
00840                 // +x
00841                 triangle_indices.push_back(1);
00842                 triangle_indices.push_back(0);
00843                 triangle_indices.push_back(2);
00844 
00845                 triangle_indices.push_back(1);
00846                 triangle_indices.push_back(2);
00847                 triangle_indices.push_back(3);
00848 
00849                 // -y
00850                 triangle_indices.push_back(3);
00851                 triangle_indices.push_back(2);
00852                 triangle_indices.push_back(7);
00853 
00854                 triangle_indices.push_back(7);
00855                 triangle_indices.push_back(2);
00856                 triangle_indices.push_back(6);
00857 
00858                 // -x
00859                 triangle_indices.push_back(7);
00860                 triangle_indices.push_back(6);
00861                 triangle_indices.push_back(4);
00862 
00863                 triangle_indices.push_back(7);
00864                 triangle_indices.push_back(4);
00865                 triangle_indices.push_back(5);
00866 
00867                 // +y
00868                 triangle_indices.push_back(5);
00869                 triangle_indices.push_back(4);
00870                 triangle_indices.push_back(1);
00871 
00872                 triangle_indices.push_back(1);
00873                 triangle_indices.push_back(4);
00874                 triangle_indices.push_back(0);
00875 
00876                 // +z
00877                 triangle_indices.push_back(0);
00878                 triangle_indices.push_back(4);
00879                 triangle_indices.push_back(6);
00880 
00881                 triangle_indices.push_back(0);
00882                 triangle_indices.push_back(6);
00883                 triangle_indices.push_back(2);
00884 
00885                 // -z
00886                 triangle_indices.push_back(7);
00887                 triangle_indices.push_back(5);
00888                 triangle_indices.push_back(3);
00889 
00890                 triangle_indices.push_back(3);
00891                 triangle_indices.push_back(5);
00892                 triangle_indices.push_back(1);
00893 
00894                 // scale the mesh points
00895                 LLVector3 big_scale(1.f, 2.f, 3.f);
00896                 std::vector< LLVector3 > new_points;
00897                 for (S32 p = 0; p < (S32)points.size(); ++p)
00898                 {
00899                         LLVector3 new_point = points[p];
00900                         for (S32 i = 0; i < 3; ++i)
00901                         {
00902                                 new_point.mV[i] *= big_scale.mV[i];
00903                         }
00904                         new_points.push_back( new_point );
00905                 }
00906 
00907                 // build the big mesh box (primitive)
00908                 LLPrimMassProperties mesh_box;
00909                 mesh_box.setUnitMesh(new_points, triangle_indices);
00910 
00911                 F32 density = DEFAULT_OBJECT_DENSITY;
00912                 LLVector3 unit_scale(1.f, 1.f, 1.f);
00913                 LLObjectMassProperties big_box(mesh_box, unit_scale, density);
00914                 
00915                 // build the multi-prim box (object)
00916                 S32 TEST_VOLUME_DETAIL = 1;
00917 
00918                 LLVolumeParams volume_params;
00919                 volume_params.setCube();
00920                 
00921                 LLObjectMassProperties multiple_box;
00922                 F32 small_box_size = 0.5f;
00923                 LLVector3 small_scale( small_box_size, small_box_size, small_box_size);
00924                 {
00925                         // hijack the volume manager used by LLPrimitive
00926                         LLPhysicsVolumeManager* volume_manager = new LLPhysicsVolumeManager();
00927                         //volume_manager->setThreadSafe(false);
00928                         LLPrimitive::setVolumeManager(volume_manager);
00929 
00930                         std::vector< const LLPrimitive* > prim_list;
00931         
00932                         F32 angle = 0.f;
00933                         LLVector3 axis(0.f, 0.f, angle);
00934                         LLVector3 position;
00935                         LLQuaternion rotation(angle, axis);
00936                         S32 num_boxes_x = S32(big_scale.mV[VX] / small_box_size);
00937                         S32 num_boxes_y = S32(big_scale.mV[VY] / small_box_size);
00938                         S32 num_boxes_z = S32(big_scale.mV[VZ] / small_box_size);
00939         
00940                         for (S32 x = 0; x < num_boxes_x; ++x)
00941                         {
00942                                 for (S32 y = 0; y < num_boxes_y; ++y)
00943                                 {
00944                                         for (S32 z = 0; z < num_boxes_z; ++z)
00945                                         {
00946                                                 LLPrimitive* primp = new LLPrimitive();
00947                                                 primp->setVolume( volume_params, TEST_VOLUME_DETAIL);
00948         
00949                                                 position.set( F32(x) * small_box_size, F32(y) * small_box_size, F32(z) * small_box_size );
00950                                                 position *= rotation;
00951         
00952                                                 primp->setPosition(position);
00953                                                 primp->setRotation(rotation);
00954                                                 primp->setScale(small_scale);
00955         
00956                                                 prim_list.push_back(primp);
00957                                         }
00958                                 }
00959                         }
00960         
00961                         volume_manager->getObjectMassProperties(multiple_box, prim_list);
00962         
00963                         for (S32 i = 0; i < (S32)prim_list.size(); ++i)
00964                         {
00965                                 delete prim_list[i];
00966                                 prim_list[i] = NULL;
00967                         }
00968                         LLPrimitive::cleanupVolumeManager();
00969                 }
00970 
00971                 // mass
00972                 F32 big_mass = big_box.getMass();
00973                 F32 multiple_mass = multiple_box.getMass();
00974                 F32 error = (big_mass - multiple_mass) / big_mass;
00975                 ensure("Big box and equivalent multi-prim box should have same mass", error < SMALL_RELATIVE_ERROR);
00976 
00977                 // center of mass
00978                 LLVector3 big_center, multiple_center;
00979                 big_box.getCenterOfMass(big_center);
00980                 multiple_box.getCenterOfMass(multiple_center);
00981                 LLVector3 expected_shift = 0.5f * ( big_scale - small_scale );
00982                 error = ( big_center - (multiple_center - expected_shift) ).length();
00983                 ensure("Big box and equivalent multi-prim box should have same center", error < SMALL_RELATIVE_ERROR);
00984 
00985                 // inertia
00986                 LLMatrix3 big_inertia, multiple_inertia;
00987                 big_box.getInertiaLocal(big_inertia);
00988                 multiple_box.getInertiaLocal(multiple_inertia);
00989 
00990                 for (S32 i = 0; i < 3; ++i)
00991                 {
00992                         for (S32 j = 0; j < 3; ++j)
00993                         {
00994                                 error = fabs(big_inertia.mMatrix[i][j] - multiple_inertia.mMatrix[i][j]);
00995                                 if (error > 0.f
00996                                         && big_inertia.mMatrix[i][j] > SMALL_RELATIVE_ERROR)
00997                                 {
00998                                         error /= big_inertia.mMatrix[i][j];
00999                                 }
01000                                 bool ok = error < SMALL_RELATIVE_ERROR
01001                                                   || (i != j 
01002                                                           && error < SMALL_RELATIVE_ERROR);
01003                                 ensure("UnitBox and UnitMesh(box) should have same inertia", ok );
01004                         }
01005                 }
01006         }
01007 }
01008 

Generated on Fri May 16 08:34:31 2008 for SecondLife by  doxygen 1.5.5