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;
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
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
00067
00068 LLMatrix3 inertia;
00069 obj_sphere.getInertiaLocal(inertia);
00070 F32 computed_inertia_eigenvalue = inertia.mMatrix[0][0];
00071
00072
00073
00074
00075
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
00091
00092
00093
00094
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
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
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
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
00148 LLInertiaTensorUtils::shiftCenteredInertiaTensor(inertia, first_shift, mass);
00149 center += first_shift;
00150
00151
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
00160 LLInertiaTensorUtils::centerInertiaTensor(inertia, third_shift, mass);
00161 center -= third_shift;
00162
00163
00164 LLInertiaTensorUtils::scaleInertiaTensor(inertia, fourth_scale);
00165
00166
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
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
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
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
00205
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
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
00232 {
00233 LLPrimMassProperties mesh;
00234 mesh.setUnitMesh(points, triangle_indices);
00235
00236
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
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
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
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
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
00296
00297
00298
00299
00300
00301
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
00325
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
00346 {
00347 LLPrimMassProperties tetrahedron;
00348 tetrahedron.addSignedTetrahedron(1.f, points[0], points[1], points[2], points[3]);
00349
00350
00351 tetrahedron.centerInertiaTensor();
00352
00353
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
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
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
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
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
00424
00425
00426 LLPrimMassProperties box;
00427 box.setUnitBox();
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
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
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
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
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
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
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
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
00514
00515
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
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
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
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
00553
00554 }
00555
00556 template<> template<>
00557 void mass_properties::test<6>()
00558 {
00559
00560
00561
00562
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
00597
00598
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
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
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
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
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
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
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
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
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
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
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
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
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
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
00772
00773
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
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
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
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
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
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
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
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
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
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
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
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
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
00926 LLPhysicsVolumeManager* volume_manager = new LLPhysicsVolumeManager();
00927
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
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
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
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