Centroid And Moments
Knowing the volume of an object isn't enough for physics simulations; we also need to know exactly where that volume is located. The Centroid is the mathematical center of an object's geometry.
Area vs Volume Centroids:
1# Center of Mass vs Area Centroid2def calculate_properties(mesh):3 """Why solid density matters."""45 # Area Centroid assumes the mesh is a hollow shell (like an empty balloon)6 # The "weight" is purely on the surface.7 area_centroid = calculate_area_centroid(mesh)89 # Volume Centroid (Center of Mass) assumes the mesh is solid all the way through10 # (like a block of cheese).11 volume_centroid = calculate_volume_centroid(mesh)1213 return area_centroid, volume_centroid
To find the Area Centroid of a complex mesh, we break the problem down to individual triangles. First, we find the centroid of each triangle (which is simply the average of its 3 vertices).
Weighted Average:
1# Calculating Area Centroid2def get_area_centroid(mesh):3 """Calculates the geometric center of the surface."""45 total_area = 0.06 weighted_centroid_sum = Vector3(0,0,0)78 for face in mesh.faces:9 v0, v1, v2 = get_vertices(mesh, face)1011 # 1. Calculate the center point of this specific triangle12 tri_center = (v0 + v1 + v2) / 3.01314 # 2. Calculate the area of this triangle15 tri_area = calculate_triangle_area(v0, v1, v2)1617 # 3. Multiply the center by the area (Weighted Sum)18 weighted_centroid_sum += (tri_center * tri_area)19 total_area += tri_area2021 # 4. Divide the total weighted sum by the total area22 final_centroid = weighted_centroid_sum / total_area2324 return final_centroid
To find the true 3D Center of Mass (Volume Centroid), we use the exact same strategy as the Area Centroid, but we use Volume instead of Area. We start by projecting every triangle to the Origin to form Tetrahedrons.
Tetrahedron Center:
v0, v1, v2 and the Origin (0,0,0). 2. The geometric center of a tetrahedron is the average of its 4 vertices. 3. Because one vertex is (0,0,0), the formula simplifies to (v0 + v1 + v2) / 4.1# Tetrahedron Centroid2def get_tetrahedron_centroid(v0, v1, v2):3 """Calculates the center of mass of a tetrahedron originating at (0,0,0)."""45 # A tetrahedron has 4 vertices: The origin (0,0,0) and the 3 triangle vertices.6 # The centroid of a tetrahedron is simply the average of its 4 vertices.78 # Since the origin is (0,0,0), we just add v0+v1+v2 and divide by 4.9 centroid = (v0 + v1 + v2) / 4.01011 return centroid
Just like with Area, we take the Weighted Average of every Tetrahedron. The elegant part of this algorithm is that because the Tetrahedron Volumes are Signed (+ or -), the Negative tetrahedrons automatically subtract their "weight" from the empty space, leaving us with the exact Center of Mass of the solid object.
Signed Weighting:
1# Calculating Volume Centroid2def get_volume_centroid(mesh):3 """Calculates the Center of Mass of a solid mesh."""45 total_volume = 0.06 weighted_centroid_sum = Vector3(0,0,0)78 for face in mesh.faces:9 v0, v1, v2 = get_vertices(mesh, face)1011 # 1. Calculate Signed Tetrahedron Volume12 tet_vol = calculate_signed_volume(v0, v1, v2)1314 # 2. Calculate Tetrahedron Centroid15 tet_center = (v0 + v1 + v2) / 4.01617 # 3. Add to the Weighted Sum18 # Note: tet_vol can be negative! This perfectly subtracts19 # the center-of-mass contribution of the empty space.20 weighted_centroid_sum += (tet_center * tet_vol)21 total_volume += tet_vol2223 # 4. Divide sum by total volume24 final_centroid = weighted_centroid_sum / total_volume2526 return final_centroid
If you push an object, the Center of Mass tells you how it accelerates. But if you spin an object, you need to know its Moments of Inertia. This describes how resistant the object is to rotation around different axes.
Rotational Resistance:
(0,0,0). 2. For every tetrahedron, integrate the square of the distance from the axis of rotation. 3. Mass that is far away from the axis creates a high moment of inertia (hard to spin). 4. Mass close to the axis creates a low moment of inertia (easy to spin, like an ice skater pulling their arms in).1# Calculating Moments of Inertia2def get_inertia_tensor(mesh, center_of_mass):3 """Calculates rotational resistance around the X, Y, and Z axes."""45 Ixx = Iyy = Izz = 0.067 for face in mesh.faces:8 v0, v1, v2 = get_vertices(mesh, face)910 # Move vertices relative to the Center of Mass11 v0 -= center_of_mass12 v1 -= center_of_mass13 v2 -= center_of_mass1415 # Calculate volume of this tetrahedron16 vol = calculate_signed_volume(v0, v1, v2)1718 # Integrate (y^2 + z^2) for Ixx, (x^2 + z^2) for Iyy, etc.19 # This requires expanding a complex polynomial over the tetrahedron domain20 Ixx += integrate_tetrahedron_inertia(v0, v1, v2, vol, axis='X')21 Iyy += integrate_tetrahedron_inertia(v0, v1, v2, vol, axis='Y')22 Izz += integrate_tetrahedron_inertia(v0, v1, v2, vol, axis='Z')2324 return Matrix3x3(Ixx, 0, 0, 0, Iyy, 0, 0, 0, Izz)
Inertia calculated along the world X, Y, and Z axes isn't very useful if the object is rotated diagonally! To find the true, natural spinning axes of a shape, we must calculate its Principal Axes.
Eigenvalue Decomposition:
1# Finding Principal Axes (Eigenvectors)2def get_principal_axes(inertia_tensor):3 """Calculates the natural spinning axes of the object."""45 # 1. The inertia tensor is a 3x3 Symmetric Matrix.6 # 2. We calculate its Eigenvalues and Eigenvectors.7 eigenvalues, eigenvectors = calculate_eigen(inertia_tensor)89 # Eigenvalues = The Principal Moments of Inertia (scalars)10 # Eigenvectors = The Principal Axes (3 orthogonal 3D vectors)1112 # Sort them by magnitude (Major, Mid, Minor axes)13 sorted_axes = sort_by_eigenvalue(eigenvalues, eigenvectors)1415 return sorted_axes
Knowing the Principal Axes allows engineers to predict how an object will tumble in zero gravity (or when thrown in the air). The Tennis Racket Theorem (Dzhanibekov Effect) proves that an object will spin stably around its Major and Minor inertia axes, but spinning it around its Intermediate axis is fundamentally chaotic and unstable.
Rotational Stability:
1# Dzhanibekov Effect (Tennis Racket Theorem)2def simulate_spin(inertia_tensor, initial_angular_velocity):3 """Why spinning around the middle axis is unstable."""45 # 1. Get the Principal Axes (Major, Mid, Minor)6 axes = get_principal_axes(inertia_tensor)78 # 2. Physics shows that rotating around the Major (highest inertia)9 # and Minor (lowest inertia) axes is perfectly stable.1011 # 3. Rotating around the Intermediate (Mid) axis is mathematically unstable!12 # A tiny perturbation will cause the object to flip 180 degrees back and forth.1314 return apply_rigid_body_dynamics(axes, initial_angular_velocity)