Python: Stacking/Distributing objects using bounding box information

Python: Stacking/Distributing objects using bounding box information

gabriellewills
Explorer Explorer
1,496 Views
3 Replies
Message 1 of 4

Python: Stacking/Distributing objects using bounding box information

gabriellewills
Explorer
Explorer

 

from maya import cmds as mc
import random


def buildSkyscraper(numFloors):
    
    #Checks for and deletes existing building
    if mc.objExists('Building_GRP'):
        mc.delete('Building_GRP')
    
    #creates a list of base objects
    base = mc.ls(selection = True)
    #greats a group for floors of building
    floorGRP = mc.group(n = 'Building_GRP'.format(base), em = True)

    mc.select(base)
    
    selList = mc.ls(selection = True)

    #creates a copy of the object,distributes each object in the tower
    for f in range(numFloors):
        obj = mc.duplicate(random.choice(selList), n = 'Building_floor{1}'.format(selList, (f + 1)))
        bbox = mc.exactWorldBoundingBox()
        yMove = (bbox[4] - bbox[1])
        moveIt = (yMove * (f))
        mc.setAttr('%s.translateY' % (obj[0]), moveIt)

    my_list = mc.ls('*Building_floor*', tr = True)

    #parents object under building group
    for m in my_list:
        mc.parent(m, floorGRP)
    
    #hides original objects
    for s in selList:
        mc.hide(s)

buildSkyscraper(15)

 

 

 

Hi All, 

 

I have written the above code as an exercise in using bounding box information to distribute objects in a stack or tower. It works as is, using any number of "base" objects and randomly distributing them to the value specified IF all of the objects are the same height.

 

I have tried a few ways to manipulate this code so that if I have objects of different heights that they stack themselves on top of the last "floor" created. I have run into a few issues sorting this out.  I can code it to do this but only if I make a few assumptions to make the math work around these assumptions. I would prefer to write the code that does not assume what the users "base" objects may be and can work with any geometry selected.

 

Thanks for your help, any suggestions are greatly appreciated.

Gabs

0 Likes
Accepted solutions (1)
1,497 Views
3 Replies
Replies (3)
Message 2 of 4

Rourker27
Contributor
Contributor
Accepted solution

You're very close to the solution, you just need to keep track of the overall height of the tower and use that as your translation offset.

This code should work:

 

from maya import cmds as mc
import random


def buildSkyscraper(numFloors):
    
    #Checks for and deletes existing building
    if mc.objExists('Building_GRP'):
        mc.delete('Building_GRP')
    
    #creates a list of base objects
    base = mc.ls(selection = True)
    #greats a group for floors of building
    floorGRP = mc.group(n = 'Building_GRP'.format(base), em = True)

    mc.select(base)
    
    selList = mc.ls(selection = True)

    towerHeight = 0 # set initial tower height

    #creates a copy of the object,distributes each object in the tower    
    for f in range(numFloors):        
        obj = mc.duplicate(random.choice(selList), n = 'Building_floor{1}'.format(selList, (f + 1)))
        bbox = mc.exactWorldBoundingBox(obj)
        
        yMove = towerHeight #set yMove
        
        #yMove = (bbox[4] - bbox[1])
        moveIt = yMove
        mc.setAttr('%s.translateY' % (obj[0]), moveIt)
        
        towerHeight = towerHeight + (bbox[4] - bbox[1]) #add bounding box to towerHeight
        

    my_list = mc.ls('*Building_floor*', tr = True)

    #parents object under building group
    for m in my_list:
        mc.parent(m, floorGRP)
    
    #hides original objects
    for s in selList:
        mc.hide(s)

buildSkyscraper(15)

 

0 Likes
Message 3 of 4

Rourker27
Contributor
Contributor

I should also say that your building blocks should be frozen/zeroed and have their pivot at the bottom center of the blocks for this to work properly.

0 Likes
Message 4 of 4

gabriellewills
Explorer
Explorer

Thanks so much, mate. That has done the trick. 

I added in a loop to snap all the objects to 0 and move their pivots to the bottom. I am not sure it is the most elegant way to code this but it works. I have attached the extra snippet it for anyone playing along.

Thanks again for your help 🙂

 

my_objects = mc.ls(selection = True)

for o in my_objects:
        mc.move(0, 0, 0, ws = True)
        bbox = mc.exactWorldBoundingBox()
        bottom = [(bbox[0] + bbox[3]) / 2, bbox[1], (bbox[2] + bbox[5]) / 2]
        cmds.xform(o, piv = bottom, ws = True)