I would like to translate a group of objects to the world origin, so that the center of mass of this group sits at the origin. I wanted to proceed as follow:
- Retrieve the center (x,y,z) of the group of objects
- Position an empty at that position
- Set all the objects as child of the empty
- Set the location of the empty to (0,0,0)
- Free up the linking and delete the empty
Steps 1 & 2 are fine. On step #3 when parenting to the empty, all child objects are offset by the absolute position of the empty. When moving the empty to (0, 0, 0) the child objects go back to their original position.
The code below illustrate this:
import bpy
import numpy as np
# Create some cubes for the sake of it
k = 3
bpy.ops.mesh.primitive_cube_add(size=2, location=(k, 2*k, 2*k+1))
bpy.ops.mesh.primitive_cube_add(size=2, location=(2*k, k, 2*k+1))
bpy.ops.mesh.primitive_cube_add(size=2, location=(2*k+1, 0, 2*k))
obj_centers = []
# Get all selected objects
for obj in bpy.context.scene.objects:
bpy.context.view_layer.objects.active = obj
if obj.type == 'MESH':
# retrieve their location
obj_center = [obj.location[0],obj.location[1], obj.location[2]]
obj_centers.append(obj_center)
#Compute the geometric center of the collection (average on x/y/z)
center = np.mean(np.asarray(obj_centers), axis=0)
# Create an empty at that location
o = bpy.data.objects.new( "my_temp_empty", None )
bpy.context.scene.collection.objects.link( o )
o.empty_display_size = 1
o.empty_display_type = 'ARROWS'
o.location = (center.tolist()[0], center.tolist()[1], center.tolist()[0])
# Parent all objects to this empty
for obj in bpy.context.scene.objects:
bpy.context.view_layer.objects.active = obj
if obj.type == 'MESH':
obj.parent = o
obj.matrix_parent_inverse = o.matrix_world.inverted()
# Move empty to origin
o.location = (0, 0, 0)
Of course, I can circumvent the problem by defining the position of the empty to the negative of the center of the objects group o.location = (-center.tolist()[0], -center.tolist()[1], -center.tolist()[0])
, but I'd prefer to understand what's going on here. It has to do with obj.matrix_parent_inverse = o.matrix_world.inverted()
this is supposed to fix the position of the children, but it does not work and I can not get my head around it (sorry, Blender beginner...).
My questions:
- is there an alternative to my approach to move the center of a group of objects to the origin?
- Are some my issues due to using an "empty" as parent?
- Could someone explain or point to a good explanation of what's going on with the position matrix when parenting. This is at the core of how Blender works, I'd be happy to finally understand it.
- How would I come to release the linking and have my objects stay at their new location (i.e Clear and Keep Transform)?
Many thanks in advance.