A bit late to answer this, but I recently had to compute the center of gravity of various objects, so here is what I got.
1) "origin to center of mass" does not put the origin to the center of mass
What this command does is to consider the object as an empty shell, i.e. it computes the centroid of all faces. This is not the same thing as the center of mass of a solid object with constant density.
2) as far as I know there is no builtin feature to compute the center of mass of a solid object.
See this answer for a basic script that does the job.
3) to be useful, center of mass computation has to consider various ways of defining actual mass.
Some objects will represent some material with constant density (a bowling ball is indeed a mass of plastic). Some will rather be the abstraction of a complex object of known weight (for instance the engine of a car). Lastly, some curves might represent ropes, rods or wires with a known linear weight (the spring of a clamp)
Based on all this, I designed a small script that does compute the center of mass of a collection of heterogenous objects.
3 kinds of objects can take part in the computation:
- meshes with a custom weight attribute
- meshes with a material that has a custom density attribute
- curves with a material that has a custom linear weight attribute
To use it, you have to define the various attributes and materials required, then you just select all the objects you want (selecting "weightless" objects, empties, whatever will do no harm) and run the script. It will place the 3D cursor at the resulting CG location.
As an illustration, see how the CG moves:
Battery placed further back
Landing gear down
I used millimeters and grams as units in my case, so if you want to switch to imperial system or change the scale you'll have to tweak a few constants. See the script for details.
from mathutils import Vector
def triangles (verts):
"""enumerate triangles in a face"""
for i in range (1, len(verts)-1):
yield (verts, verts[i], verts[i+1])
def cg_mesh (obj):
"""center of gravity and mass of a mesh"""
center = Vector()
volume = 0
mesh = obj.to_mesh (bpy.context.scene, True, 'PREVIEW')
for face in mesh.polygons:
f = face.vertices
for t in triangles (f):
a,b,c = (mesh.vertices[v].co for v in t)
v = a.cross(b).dot(c) / 6
center += v * (a+b+c) / 4
volume += v
if volume == 0: print ("ZERO VOLUME", obj.name)
else : center /= volume
# To make a mesh heavy
# define a "weight" (in grams) custom property at object level, or
# define a "density" (in g/cm3) custom property in associated material
if 'weight' in obj:
mass = obj['weight']
elif obj.active_material and 'density' in obj.active_material:
mass = volume * obj.active_material['density'] / 1000
mass = 0
return center, mass
def cg_curve (obj):
"""center of gravity and mass of a curve"""
# to make a curve heavy,
# define a "linear weight" (in g/m) custom property in associated material
linear_weight = obj.active_material['linear weight'] / 1000
print ("NO MATERIAL FOR CURVE", obj.name)
return Vector(), 0
# copy the curve and its modifiers
bones = obj.copy()
bones.data = obj.data.copy() # copy curve
curve = bones.data
# reduce curve to skeleton
curve.bevel_object = None
curve.taper_object = None
# convert to mesh, applying modifiers
mesh = bones.to_mesh (bpy.context.scene, True, 'PREVIEW')
# compute skeleton length and center of mass
len = 0
center = Vector()
for segment in mesh.edges:
a, b = (mesh.vertices[v].co for v in segment.vertices)
l = (a-b).length
center += l * (a+b) # / 2 (median point) taken out of the loop
len += l
return center/len/2, len * linear_weight
def cg_switch (obj):
if obj.type == 'MESH' : return cg_mesh (obj)
elif obj.type == 'CURVE': return cg_curve(obj)
else : return Vector(), 0
def cg (obj):
center, mass = cg_switch (obj)
return obj.matrix_world * center, mass
center = Vector()
weight = 0
for obj in bpy.context.selected_objects:
c, w = cg (obj)
center += c * w
weight += w
if weight != 0:
bpy.context.scene.cursor_location = center/weight
print (center/weight, weight)