1
$\begingroup$

I am trying to calculate the cooordinates of the center of a group of objects using this code:

obj = bpy.context.active_object                                             
vcos = [ obj.matrix_world * v.co for v in obj.data.vertices ]                     
findCenter = lambda l: ( max(l) + min(l) ) / 2      
x,y,z  = [ [ v[i] for v in vcos ] for i in range(3) ]      
center = [ findCenter(axis) for axis in [x,y,z] ]

The problem is that "bpy.context.active_object" returns only the (bpy_struct, Object) of one OBJECT only (the first to render) and does not consider the other objects. As a result the obtained X,Y,Z coordinates are only correct for one object and not all of them.

Any solution?

Amir

$\endgroup$
3
  • 1
    $\begingroup$ try bpy.context.selected_objects $\endgroup$
    – Gorgious
    Sep 9, 2020 at 13:48
  • $\begingroup$ @Gorgious: This gives ('list' object has no attribute 'data') this is attribute of vertices used later in the code. I use this code after rendering, so I have a loop and I render hide some objects and render others and in each time I render an individual object I wanna get it X,Y,Z coordinates. For some rason, when I print the coordinates of (center) of each object rendered separately in the loop, i find the same coordinates and I find "obj" is only referring to the first rendered object and does not change when I render the other objects. Any advise???? $\endgroup$
    – Amir Aly
    Sep 9, 2020 at 14:47
  • $\begingroup$ What is not clear for me: do you want the center considering all objects at once (so 1 center for all) or the center for each object? (@Gorgious) $\endgroup$
    – lemon
    Sep 9, 2020 at 15:04

2 Answers 2

2
$\begingroup$

Take this image : enter image description here

bpy.context.active_object only gives a reference to the active object in the given context. This is Cube.002, with the light orange outline.

Cube is selected, but it is not the active object. (dark orange outline).

When you type bpy.context.selected_objects in the blender console you get an unordered list of all the selected objects.

>>> bpy.context.selected_objects
[bpy.data.objects['Cube'], bpy.data.objects['Cube.002']]

In python you can iterate through a list of objects with a for loop. (Documentation) Your code, which is valid for one object, can be translated for a list to :

import bpy

for obj in bpy.context.selected_objects:
    if obj.type != 'MESH':
        continue
    # Sidenote : Use @ instead of * for element-wise multiplication in matrices          
    vcos = [ obj.matrix_world @ v.co for v in obj.data.vertices ]                     
    findCenter = lambda l: ( max(l) + min(l) ) / 2      
    x,y,z  = [ [ v[i] for v in vcos ] for i in range(3) ]      
    center = [ findCenter(axis) for axis in [x,y,z] ]
    
    print(center)

Result :

enter image description here

$\endgroup$
2
  • $\begingroup$ Given the OP's new question might pay to put the type checking in loop, eg if obj.type != 'MESH' : continue to avoid trying to process vertices of non mesh objects. blender.stackexchange.com/questions/196663/… $\endgroup$
    – batFINGER
    Oct 7, 2020 at 13:54
  • $\begingroup$ @batFINGER Good point ! Edited answer $\endgroup$
    – Gorgious
    Oct 7, 2020 at 14:07
1
$\begingroup$

Bounds center is the middle of the bounding box.

The local positions of the axis oriented bounding box of a mesh are generated for us and available in the object's bounding box property in local coordinates.

The average of the bounding boxes 8 corner coordinates give the local center, which can be converted to global by multiplying by matrix world of owner.

Pros, only summing 8 coordinates per object and matrix multiplying once Using the object's vertices is unnecessary overhead.

import bpy
from mathutils import Vector
# mesh objects in scene
scene = bpy.context.scene
mesh_obs = [o for o in scene.objects if o.type == 'MESH']

for ob in mesh_obs:
    bbox_local_center = sum((Vector(b) for b in ob.bound_box), Vector()) / 8
    center = ob.matrix_world @ bbox_local_center
    print(f"{ob.name} {center}")

Thought this rang a bell, possible duplicate and source of question code. Get center of geometry of an object If you source code from elsewhere, providing a link gives context.

Note.

If instead you wish to get the "global bounding box" of all recommend using numpy.

import bpy
import numpy as np

# mesh objects in scene
scene = bpy.context.scene
mesh_obs = [o for o in scene.objects if o.type == 'MESH']
# stack global coords of bboxes of all objects in scene
coords = np.vstack(
    (np.dot(
        np.hstack(
            (np.array(ob.bound_box),
             np.ones(8).reshape(8, 1))
             ), 
        ob.matrix_world.transposed()
        )
    for ob in mesh_obs)
    )

#bottom front left corner, top, right back corner    
print(coords.min(), coords.max())
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .