Display a single bounding box for multiple objects?

I’ve got hundreds of thousands of objects in a scene and would like to have some representation of them without the incredible slow down that comes from displaying that many individual bounding boxes.

Is it possible? (Without resorting to particle instancing)

Can you set up LODs for them or some other visual proxy? A quad for instance? Part of the slowdown with bounding boxes is the wireframe drawing…

You can use LOD groups ( Edit > Level Of Detail > Group ) to swap in more manageable proxy geometry.

This snippet will generate a world space BB for a hierarchy, so you could define LOD groups at different levels of the hierarchy and have them swap to single box objects:


def generate_bbox( obj ):
    '''
    returns the world space bounding box of transform node <obj> as a mesh
    '''
    bbx = cmds.xform( obj, q=True, wd=True, bbi=True ) 
    w = ( bbx[3] - bbx[0] )
    h = ( bbx[4] - bbx[1] )
    d = ( bbx[5] - bbx[2] )
    x = ( bbx[3] + bbx[0] ) / 2.0
    y = ( bbx[4] + bbx[1] ) / 2.0
    z = ( bbx[5] + bbx[2] ) / 2.0
    res = cmds.polyCube( width=w, depth=d, height=h ) #@UndefinedVariable
    cmds.polyMoveVertex( tx=x, ty=y, tz=z )
    return res[0]

The xform command has a limitation due to its architecture:
This command can only work with a transform node, and only with a single transform node

Instead of:

bbx = cmds.xform( obj, q=True, wd=True, bbi=True )

you can use:

bbx = cmds.exactWorldBoundingBox( obj, ii=False, ce=False )

MAYA HELP : exactWorldBoundingBox

This command figures out an exact-fit bounding box for the specified objects (or selected objects if none are specified) This bounding box is always in world space.


exactWorldBoundingBox( [dagObject...] , [calculateExactly=boolean], [ignoreInvisible=boolean])

Flags:

calculateExactly(ce) boolean, create mode
Should the bounding box calculation be exact?

ignoreInvisible(ii) boolean, create mode
Should the bounding box calculation include or exclude invisible objects?

Python example:


sel = ['set1', 'set2', 'pCube1', 'pCubeShape2', 'group1', 'spotLight1', 'directionalLight1']

bbox = cmds.exactWorldBoundingBox( sel, ignoreInvisible = False, calculateExactly = False)

The calculateWorldBoundingBox command can correctly return the bounding box for invisible objects.
When the calculateExactly flag is disabled, the bounding box calculation is very fast (this is important when you are passing thousands of objects as an argument).
And most importantly, the calculateWorldBoundingBox command can take almost any combination of objects as an argument: you can pass the name of the set (s) either individually or together with a list of transformation nodes and mesh nodes.

import maya.cmds as cmds
import maya.api.OpenMaya as om


def generate_bbox( goal_obj ):

    exWBB = cmds.exactWorldBoundingBox(goal_obj, ii = False, ce = False)

    # We substitute the received values in the Maya API MBoundingBox.
    # This will allow us to obtain, without additional calculations,
    # such properties of the bounding box as:
    # width - Width (size in X) of bounding box.
    # height - 	Height (size in Y) of bounding box.
    # depth - Depth (size in Z) of bounding box.
    # center - Center of bounding box.
    # max - Bounding box's maximum values.
    # min - Bounding box's minimum values.

    bbox = om.MBoundingBox(om.MPoint(exWBB[0], exWBB[1], exWBB[2], 1),
                           om.MPoint(exWBB[3], exWBB[4], exWBB[5], 1))

    # Let's create a polycube and get a string of its name.
    # For best performance, disable construction history and disable UV creation.

    poly_cube = cmds.polyCube(constructionHistory = False,
                                        createUVs = False,
                                          texture = False,
                                             name = 'LOD_BBox_0001',
                                            width = bbox.width,
                                           height = bbox.height,
                                            depth = bbox.depth)[0]

    cmds.xform('{}.vtx[*]'.format(poly_cube),
               relative = True,
               translation = [bbox.center.x, bbox.center.y, bbox.center.z])

    # To improve performance, turn off shading and texturing
    # and assign a more saturated color to the wireframe.

    cmds.setAttr('{}.overrideEnabled'.format(poly_cube), 1)
    cmds.setAttr('{}.overrideShading'.format(poly_cube), 0)
    cmds.setAttr('{}.overrideTexturing'.format(poly_cube), 0)
    cmds.setAttr('{}.overrideColor'.format(poly_cube), 17)


generate_bbox( sel )

:slight_smile:

You should try gpu caches.