Here’s a script that visualizes the bounding boxes and axis-aligned bounding box of these boxes (this can be larger than the actual min/max extends of vertices in the meshes):
import bpy
import bgl
from mathutils import Vector
def draw_callback_px(self, context):
ob = context.object
if ob is None or ob.type not in ('MESH', 'CURVE', 'SURFACE', 'META', 'FONT'):
# Type that doesn't support .bound_box
return
mat = ob.matrix_world
# 50% alpha, 2 pixel width line
bgl.glEnable(bgl.GL_BLEND)
bgl.glColor4f(1.0, 0.0, 0.0, 0.5)
bgl.glLineWidth(2)
bboxes = []
for ob in context.selected_objects:
if ob.type == 'MESH':
bbox = [ob.matrix_world * Vector(b) for b in ob.bound_box]
bboxes.extend(bbox)
bgl.glBegin(bgl.GL_LINE_STRIP)
bgl.glVertex3f(*bbox[0])
bgl.glVertex3f(*bbox[1])
bgl.glVertex3f(*bbox[2])
bgl.glVertex3f(*bbox[3])
bgl.glVertex3f(*bbox[0])
bgl.glVertex3f(*bbox[4])
bgl.glVertex3f(*bbox[5])
bgl.glVertex3f(*bbox[6])
bgl.glVertex3f(*bbox[7])
bgl.glVertex3f(*bbox[4])
bgl.glEnd()
bgl.glBegin(bgl.GL_LINES)
bgl.glVertex3f(*bbox[1])
bgl.glVertex3f(*bbox[5])
bgl.glVertex3f(*bbox[2])
bgl.glVertex3f(*bbox[6])
bgl.glVertex3f(*bbox[3])
bgl.glVertex3f(*bbox[7])
bgl.glEnd()
min_x = min(b.x for b in bboxes)
max_x = max(b.x for b in bboxes)
min_y = min(b.y for b in bboxes)
max_y = max(b.y for b in bboxes)
min_z = min(b.z for b in bboxes)
max_z = max(b.z for b in bboxes)
bgl.glColor4f(0.0, 1.0, 0.0, 0.5)
bgl.glBegin(bgl.GL_LINE_STRIP)
bgl.glVertex3f(min_x, min_y, min_z)
bgl.glVertex3f(min_x, max_y, min_z)
bgl.glVertex3f(max_x, max_y, min_z)
bgl.glVertex3f(max_x, min_y, min_z)
bgl.glVertex3f(min_x, min_y, min_z)
bgl.glVertex3f(min_x, min_y, max_z)
bgl.glVertex3f(min_x, max_y, max_z)
bgl.glVertex3f(max_x, max_y, max_z)
bgl.glVertex3f(max_x, min_y, max_z)
bgl.glVertex3f(min_x, min_y, max_z)
bgl.glEnd()
bgl.glBegin(bgl.GL_LINES)
bgl.glVertex3f(max_x, min_y, min_z)
bgl.glVertex3f(max_x, min_y, max_z)
bgl.glVertex3f(min_x, max_y, min_z)
bgl.glVertex3f(min_x, max_y, max_z)
bgl.glVertex3f(max_x, max_y, min_z)
bgl.glVertex3f(max_x, max_y, max_z)
bgl.glEnd()
# restore opengl defaults
bgl.glLineWidth(1)
bgl.glDisable(bgl.GL_BLEND)
bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
class ModalDrawOperator(bpy.types.Operator):
"""Draw a line with the mouse"""
bl_idname = "view3d.modal_operator"
bl_label = "Simple Modal View3D Operator"
def modal(self, context, event):
context.area.tag_redraw()
if event.type in {'ESC'}:
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
return {'CANCELLED'}
return {'PASS_THROUGH'}
def invoke(self, context, event):
if context.area.type == 'VIEW_3D':
# the arguments we pass the the callback
args = (self, context)
# Add the region OpenGL drawing callback
# draw in view space with 'POST_VIEW' and 'PRE_VIEW'
self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, args, 'WINDOW', 'POST_VIEW')
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
self.report({'WARNING'}, "View3D not found, cannot run operator")
return {'CANCELLED'}
def register():
bpy.utils.register_class(ModalDrawOperator)
def unregister():
bpy.utils.unregister_class(ModalDrawOperator)
if __name__ == "__main__":
register()
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
context = bpy.context.copy()
context['area'] = area
bpy.ops.view3d.modal_operator(context, 'INVOKE_DEFAULT')
break