PolyhedralMassProperties.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Matrix3x3.h>
  9. namespace WwiseGTE
  10. {
  11. // The input triangle mesh must represent a polyhedron. The triangles are
  12. // represented as triples of indices <V0,V1,V2> into the vertex array.
  13. // The index array has numTriangles such triples. The Boolean value
  14. // 'bodyCoords is' 'true' if you want the inertia tensor to be relative to
  15. // body coordinates but 'false' if you want it to be relative to world
  16. // coordinates.
  17. //
  18. // The code assumes the rigid body has a constant density of 1. If your
  19. // application assigns a constant density of 'd', then you must multiply
  20. // the output 'mass' by 'd' and the output 'inertia' by 'd'.
  21. template <typename Real>
  22. void ComputeMassProperties(Vector3<Real> const* vertices, int numTriangles,
  23. int const* indices, bool bodyCoords, Real& mass, Vector3<Real>& center,
  24. Matrix3x3<Real>& inertia)
  25. {
  26. Real const oneDiv6 = (Real)1 / (Real)6;
  27. Real const oneDiv24 = (Real)1 / (Real)24;
  28. Real const oneDiv60 = (Real)1 / (Real)60;
  29. Real const oneDiv120 = (Real)1 / (Real)120;
  30. // order: 1, x, y, z, x^2, y^2, z^2, xy, yz, zx
  31. std::array<Real, 10> integral;
  32. integral.fill((Real)0);
  33. int const* index = indices;
  34. for (int i = 0; i < numTriangles; ++i)
  35. {
  36. // Get vertices of triangle i.
  37. Vector3<Real> v0 = vertices[*index++];
  38. Vector3<Real> v1 = vertices[*index++];
  39. Vector3<Real> v2 = vertices[*index++];
  40. // Get cross product of edges and normal vector.
  41. Vector3<Real> V1mV0 = v1 - v0;
  42. Vector3<Real> V2mV0 = v2 - v0;
  43. Vector3<Real> N = Cross(V1mV0, V2mV0);
  44. // Compute integral terms.
  45. Real tmp0, tmp1, tmp2;
  46. Real f1x, f2x, f3x, g0x, g1x, g2x;
  47. tmp0 = v0[0] + v1[0];
  48. f1x = tmp0 + v2[0];
  49. tmp1 = v0[0] * v0[0];
  50. tmp2 = tmp1 + v1[0] * tmp0;
  51. f2x = tmp2 + v2[0] * f1x;
  52. f3x = v0[0] * tmp1 + v1[0] * tmp2 + v2[0] * f2x;
  53. g0x = f2x + v0[0] * (f1x + v0[0]);
  54. g1x = f2x + v1[0] * (f1x + v1[0]);
  55. g2x = f2x + v2[0] * (f1x + v2[0]);
  56. Real f1y, f2y, f3y, g0y, g1y, g2y;
  57. tmp0 = v0[1] + v1[1];
  58. f1y = tmp0 + v2[1];
  59. tmp1 = v0[1] * v0[1];
  60. tmp2 = tmp1 + v1[1] * tmp0;
  61. f2y = tmp2 + v2[1] * f1y;
  62. f3y = v0[1] * tmp1 + v1[1] * tmp2 + v2[1] * f2y;
  63. g0y = f2y + v0[1] * (f1y + v0[1]);
  64. g1y = f2y + v1[1] * (f1y + v1[1]);
  65. g2y = f2y + v2[1] * (f1y + v2[1]);
  66. Real f1z, f2z, f3z, g0z, g1z, g2z;
  67. tmp0 = v0[2] + v1[2];
  68. f1z = tmp0 + v2[2];
  69. tmp1 = v0[2] * v0[2];
  70. tmp2 = tmp1 + v1[2] * tmp0;
  71. f2z = tmp2 + v2[2] * f1z;
  72. f3z = v0[2] * tmp1 + v1[2] * tmp2 + v2[2] * f2z;
  73. g0z = f2z + v0[2] * (f1z + v0[2]);
  74. g1z = f2z + v1[2] * (f1z + v1[2]);
  75. g2z = f2z + v2[2] * (f1z + v2[2]);
  76. // Update integrals.
  77. integral[0] += N[0] * f1x;
  78. integral[1] += N[0] * f2x;
  79. integral[2] += N[1] * f2y;
  80. integral[3] += N[2] * f2z;
  81. integral[4] += N[0] * f3x;
  82. integral[5] += N[1] * f3y;
  83. integral[6] += N[2] * f3z;
  84. integral[7] += N[0] * (v0[1] * g0x + v1[1] * g1x + v2[1] * g2x);
  85. integral[8] += N[1] * (v0[2] * g0y + v1[2] * g1y + v2[2] * g2y);
  86. integral[9] += N[2] * (v0[0] * g0z + v1[0] * g1z + v2[0] * g2z);
  87. }
  88. integral[0] *= oneDiv6;
  89. integral[1] *= oneDiv24;
  90. integral[2] *= oneDiv24;
  91. integral[3] *= oneDiv24;
  92. integral[4] *= oneDiv60;
  93. integral[5] *= oneDiv60;
  94. integral[6] *= oneDiv60;
  95. integral[7] *= oneDiv120;
  96. integral[8] *= oneDiv120;
  97. integral[9] *= oneDiv120;
  98. // mass
  99. mass = integral[0];
  100. // center of mass
  101. center = Vector3<Real>{ integral[1], integral[2], integral[3] } / mass;
  102. // inertia relative to world origin
  103. inertia(0, 0) = integral[5] + integral[6];
  104. inertia(0, 1) = -integral[7];
  105. inertia(0, 2) = -integral[9];
  106. inertia(1, 0) = inertia(0, 1);
  107. inertia(1, 1) = integral[4] + integral[6];
  108. inertia(1, 2) = -integral[8];
  109. inertia(2, 0) = inertia(0, 2);
  110. inertia(2, 1) = inertia(1, 2);
  111. inertia(2, 2) = integral[4] + integral[5];
  112. // inertia relative to center of mass
  113. if (bodyCoords)
  114. {
  115. inertia(0, 0) -= mass * (center[1] * center[1] + center[2] * center[2]);
  116. inertia(0, 1) += mass * center[0] * center[1];
  117. inertia(0, 2) += mass * center[2] * center[0];
  118. inertia(1, 0) = inertia(0, 1);
  119. inertia(1, 1) -= mass * (center[2] * center[2] + center[0] * center[0]);
  120. inertia(1, 2) += mass * center[1] * center[2];
  121. inertia(2, 0) = inertia(0, 2);
  122. inertia(2, 1) = inertia(1, 2);
  123. inertia(2, 2) -= mass * (center[0] * center[0] + center[1] * center[1]);
  124. }
  125. }
  126. }