# How can I calculate the inertia tensor of a hollow object defined by a triangle mesh?

I want to calculate the mass, center of mass, and inertia tensor of player created objects. Some of the objects will be hollow instead of solid. I am creating a closed triangle mesh for their object. Note that this is for a physics building game so I want the values to be as accurate as possible (within reason).

Based on the references listed below, I can get the properties for a solid object by creating a tetrahedron from each triangle of the mesh and calculating the signed volume which gives the mass (volume * density) and the center of mass. I even got the inertia tensor calculation working.

How do I do the same for a hollow object?

1. For the mass and center of mass, I am iterating through the triangles of the mesh and totaling their area and calculating the area-weighted average of their positions, then multiplying the surface area by a "density" value to get the mass.

 public static (float, Vector3) CalculateSurfaceArea(Mesh mesh)
{
Vector3[] vertices = mesh.vertices;
int[] triangles = mesh.triangles;

float totalArea = 0f;
Vector3 temp = Vector3.zero;

for (int i = 0; i <= triangles.Length - 3; i += 3)
{
Vector3 v1 = vertices[triangles[i]];
Vector3 v2 = vertices[triangles[i + 1]];
Vector3 v3 = vertices[triangles[i + 2]];
Vector3 edge21 = v2 - v1;
Vector3 edge31 = v3 - v1;

float area = Vector3.Cross(edge21, edge31).magnitude / 2f; // area of the triangle
totalArea += area;

Vector3 triCenter = (v1 + v2 + v3) / 3f; // center of the triangle
temp += triCenter * area;
}

Vector3 areaCenter = temp / totalArea;

return (totalArea, areaCenter);
}

2. For the inertia tensor, I am trying a similar approach where I iterate through all the triangles and total up their moments of inertia and using the parallel-axis theorem to account for their positions but (a) I am not sure this is correct and (b) how do I calculate the products of inertia (Ixy, Ixz, Iyz)?

 public static (Vector3, Quaternion) CalculateHollowInertiaTensor(Mesh mesh)
{
Vector3[] vertices = mesh.vertices;
int[] triangles = mesh.triangles;

double Ixx = 0f;
double Iyy = 0f;
double Izz = 0f;
double Ixy = 0f;
double Ixz = 0f;
double Iyz = 0f;

for (int i = 0; i <= triangles.Length - 3; i += 3)
{
Vector3 v1 = vertices[triangles[i]];
Vector3 v2 = vertices[triangles[i + 1]];
Vector3 v3 = vertices[triangles[i + 2]];
Vector3 edge21 = v2 - v1;
Vector3 edge31 = v3 - v1;
Vector3 center = (v1 + v2 + v3) / 3f; // center of the triangle
Vector3 offset = center - v1;

float area = Vector3.Cross(edge21, edge31).magnitude / 2f; // area of the triangle

// Moment of inertia of triangle rotating around the first vertex
// https://en.wikipedia.org/wiki/List_of_moments_of_inertia
// I = (1/6)m(P.P + P.Q + Q.Q)
float triIxx = (edge21.y * edge21.y + edge21.z * edge21.z + edge21.y * edge31.y + edge21.z * edge31.z + edge31.y * edge31.y + edge31.z * edge31.z) / 6f;
float triIyy = (edge21.x * edge21.x + edge21.z * edge21.z + edge21.x * edge31.x + edge21.z * edge31.z + edge31.x * edge31.x + edge31.z * edge31.z) / 6f;
float triIzz = (edge21.x * edge21.x + edge21.y * edge21.y + edge21.x * edge31.x + edge21.y * edge31.y + edge31.x * edge31.x + edge31.y * edge31.y) / 6f;

// Shift to the center of the triangle
triIxx -= offset.y * offset.y + offset.z * offset.z;
triIyy -= offset.x * offset.x + offset.z * offset.z;
triIzz -= offset.x * offset.x + offset.y * offset.y;

// Shift to the origin (using parallel-axis theorem)
triIxx += center.y * center.y + center.z * center.z;
triIyy += center.x * center.x + center.z * center.z;
triIzz += center.x * center.x + center.y * center.y;

Ixx += triIxx * area;
Iyy += triIyy * area;
Izz += triIzz * area;
//Ixy += area * center.x * center.y;
//Ixz += area * center.x * center.z;
//Iyz += area * center.y * center.z;
}

Matrix<double> inertiaTensor = Matrix<double>.Build.Dense(3, 3);
inertiaTensor[0, 0] = Ixx;
inertiaTensor[1, 1] = Iyy;
inertiaTensor[2, 2] = Izz;
inertiaTensor[0, 1] = inertiaTensor[1, 0] = -Ixy;
inertiaTensor[0, 2] = inertiaTensor[2, 0] = -Ixz;
inertiaTensor[1, 2] = inertiaTensor[2, 1] = -Iyz;

Debug.Log(inertiaTensor);

//Matrix<double> inertiaTensorInverse = inertiaTensor.Inverse();

// Find the principal axes and simplified inertia tensor
Evd<double> evd = inertiaTensor.Evd();
Vector3 inertiaTensorDiagonal = MakeVector3(evd.EigenValues.Real());
Quaternion inertiaTensorRotation = Quaternion.LookRotation(
MakeVector3(evd.EigenVectors.Column(2)),
MakeVector3(evd.EigenVectors.Column(1))
);

return (inertiaTensorDiagonal, inertiaTensorRotation);
}


References I've been using: (would like some more :))