#city generator script in python #pymel rocks btw! check out pymel.googlecode.com #script v1 #arunan rabindran, 2009 #creative commons license #This work is licensed under the Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License. To view a copy of this license, #visit http://creativecommons.org/licenses/by-nc-sa/3.0/us/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, #California, 94105, USA. ############################### #rename this file -> citygen.py ############################### ------------------------------------------------------------------------------------------------------------------------------ from pymel import * import random import math ------------------------------------------------------------------------------------------------------------------------------ #draw columns def addColumns(bldg, bname, pctBldgHt, colWidth, htOffset, xNum, zNum): ymax=bldg.boundingBoxMaxY.get() ymin=bldg.boundingBoxMinY.get() height=ymax-ymin bldg.attr("scalePivot").set([0.0, -(ymax-ymin), 0.0]) xmax=bldg.boundingBoxMaxX.get() xmin=bldg.boundingBoxMinX.get() width=xmax-xmin zmax=bldg.boundingBoxMaxZ.get() zmin=bldg.boundingBoxMinZ.get() depth=zmax-zmin #column sizes scaled to fit #colWidth = colWidth * (xmax - xmin) for i in range((xmax-xmin)/xNum+1): colXnm="colpX" + bname +"_"+ str(i) colX=polyCube(name=colXnm, w=colWidth, h=((pctBldgHt/100)*height), d=colWidth)[0] colX.translateX.set( xmin + (i*xNum))#+((xmax-xmin)/xNum) ) colX.translateZ.set( zmin ) colX.translateY.set( ((colX.boundingBoxMaxY.get()-colX.boundingBoxMinY.get())-height) / 2 ) parent(colXnm, bname) for i in range((zmax-zmin)/zNum+1): colZnm="colpZ" + bname +"_"+ str(i) colZ=polyCube(name=colZnm, w=colWidth, h=((pctBldgHt/100)*height), d=colWidth)[0] colZ.translateZ.set( zmin + (i*zNum))#+((zmax-zmin)/zNum) ) colZ.translateX.set( xmin ) colZ.translateY.set( ((colZ.boundingBoxMaxY.get()-colZ.boundingBoxMinY.get())-height) / 2 ) parent(colZnm, bname) for i in range((xmax-xmin)/xNum+1): colXnm="colnX" + bname +"_"+ str(i) colX=polyCube(name=colXnm, w=colWidth, h=((pctBldgHt/100)*height), d=colWidth)[0] colX.translateX.set( xmax - (i*xNum))#+((xmax-xmin)/xNum) ) colX.translateZ.set( zmax ) colX.translateY.set( ((colX.boundingBoxMaxY.get()-colX.boundingBoxMinY.get())-height) / 2 ) parent(colXnm, bname) for i in range((zmax-zmin)/zNum+1): colZnm="colnZ" + bname +"_"+ str(i) colZ=polyCube(name=colZnm, w=colWidth, h=((pctBldgHt/100)*height), d=colWidth)[0] colZ.translateZ.set( zmax - (i*zNum))#+((zmax-zmin)/zNum) ) colZ.translateX.set( xmax ) colZ.translateY.set( ((colZ.boundingBoxMaxY.get()-colZ.boundingBoxMinY.get())-height) / 2 ) parent(colZnm, bname) return 0 ------------------------------------------------------------------------------------------------------------------------------ #draw building def drawBuilding(bname, wd, ht, dp, gname): randVar = random.uniform(0.0, 5.0) if(randVar<=1.0): #draw cube bldg = polyCube(name=bname, w=wd, h=ht, d=dp)[0] nm = "topOf" + bname top = polyCylinder(name=nm, r=wd/20, h=ht/10)[0] maxY = bldg.boundingBoxMaxY.get() #print maxY top.translateY.set( maxY ) parent( nm, bname) addColumns(bldg, bname, 105.0, 2.0, 0.0, 10, 10) #group under group name parent( bname, gname ) if(randVar<=5.0 and randVar>2.0): #draw cube bldg = polyCylinder(name=bname, r=wd/2, h=ht)[0] nm = "topOf" + bname top = polyCube(name=nm, w=wd/10, h=ht/10, d=dp/10)[0] maxY = bldg.boundingBoxMaxY.get() #print maxY top.translateY.set( maxY ) parent( nm, bname) #group under group name parent( bname, gname ) if(randVar<=2.0 and randVar>1.0): #draw helix bldg = polyHelix(name=bname, r=dp/2, c=3, h=ht/2, w=wd/8)[0] parent( bname, gname ) # #select shape # #draw roofing # #draw faces return bldg ------------------------------------------------------------------------------------------------------------------------------ #generate city function def generate(radius, numbuildings, minH, maxH, minW, maxW, minD, maxD): f=newFile(f=1) #create terrain group group( em=True, name="ground" ) #make dummy plane ground = polyPlane(name="groundPlane", w=1, h=1, sx=1, sy=1)[0] ground.scaleX = radius ground.scaleZ = radius groundY = ground.translateY.get() parent( 'groundPlane', 'ground' ) #print groundY bldg = list() bldghts = list() #create empty group for buildings group( em=True, name="buildings" ) #buildings to be grown at random locations within city i = 1 for i in range(numbuildings+1): ht=random.uniform(minH, maxH) bname="building"+ str(i) #draw the building and add to list bldg.append( drawBuilding(bname, random.uniform(minW, maxW), ht, random.uniform(minD, maxD), "buildings" ) ) #parent( bname , 'buildings' ) #bldghts.append( ht ) bldg[i].translateX=random.uniform(-radius/2, radius/2) bldg[i].translateY=float(groundY)+(ht/2) bldg[i].translateZ=random.uniform(-radius/2, radius/2) print ground print len(bldg) print radius #animate the growth animate(radius, numbuildings, bldg, bldghts, groundY) #close window deleteUI( win, window=True ) return 0 ------------------------------------------------------------------------------------------------------------------------------ #animate growth of the city def animate(radius, numbuildings, bldgList, bldgHtList, groundY): #init scales of buildings bldgScales = list() bboxX = list() bboxY = list() bboxZ = list() sPiv = list() for i in range(numbuildings+1): bldgScales.append( bldgList[i].scaleY.get() ) #print bldgScales[i] bldgList[i].scaleY.set(0.0) bldgList[i].translateY=float(groundY) bldgList[i].scalePivotY=-1.0 bboxX.append ( bldgList[i].attr('boundingBoxMaxX').get() - bldgList[i].attr('boundingBoxMinX').get() ) bboxY.append ( bldgList[i].attr('boundingBoxMaxY').get() - bldgList[i].attr('boundingBoxMinY').get() ) bboxZ.append ( bldgList[i].attr('boundingBoxMaxZ').get() - bldgList[i].attr('boundingBoxMinZ').get() ) bldgList[i].attr('scalePivot').set([0.0, bboxY[i]/2, 0.0]) #bldgList[i].attr('movePivot').set([0.0, bboxY[i]/2, 0.0]) sPiv.append ( bldgList[i].attr('scalePivot').get() ) #print sPiv[i] #setKeyframe(bldgList[i], t=0, at='scaleY', v=0.0) #setKeyframe(bldgList[i], t=0, at='translateY', v=groundY + (bboxY[i]/2)) #setKeyframe(bldgList[i], t=600, at='scaleY', v=1.0) #setKeyframe(bldgList[i], t=600, at='translateY', v=1.0) #make locator animLocator = Locator(name="animLoc") #posX = animLocator.getPosition()[0] posY = animLocator.getPosition()[1] posZ = animLocator.getPosition()[2] posX = animLocator.attr('localPosition').get() print posX animLocRadius = radius / 10; #set position keyframe animLocator.attr('localPosition').set([radius/2, 10.0, radius/2]) setKeyframe(animLocator, t=0, at='localPositionX', v=(radius/2)+250.0) setKeyframe(animLocator, t=0, at='localPositionY', v=100.0) setKeyframe(animLocator, t=0, at='localPositionZ', v=(-radius/2)-250.0) setKeyframe(animLocator, t=1800, at='localPositionX', v=(-radius)/2+50.0) setKeyframe(animLocator, t=1800, at='localPositionY', v=100.0) setKeyframe(animLocator, t=1800, at='localPositionZ', v=(radius/2)+50.0) #expression #scale 'em up expression #->first write mel expression file #->then compile it: will see this formatted text in the script editor window #->paste the formatted expression string to create it in the pymel script.. voila! cheap automation animExp = Expression(name="scaleEmUp", string= "\tint $i;\r float $locX;\r float $bLocX;\r string $evalStr;\r float $scale = 0.0;\r float $trans = 0.0;\r float $groundY;\r\r //get location of Locator\r $locX = `getAttr locator1|animLoc.localPositionX`;\r\r //for all the buildings in the scene DO\r for($i=0; $i < 50; $i++)\r {\r //get building X position\r string $bStr = \"building\" + $i;\r int $j;\r $j = $i + 1;\r string $cbStr = \"building\" + $i;\r $evalStr = \"getAttr \\\"\" + $bStr +\".translateX\\\";\";\r $bLocX = eval($evalStr);\r \r $evalStr = \"getAttr \\\"groundPlane.translateY\\\";\";\r $groundY = eval($evalStr);\r \r if($bLocX < $locX+70.0 && $bLocX > $locX-70.0)\r { \r //get Building Scale & scale up if within range of locator\r $evalStr = \"getAttr \\\"\" + $bStr +\".scaleY\\\";\";\r $scale = eval($evalStr);\r if($scale < 1.0)\r $scale += 0.3; \r $evalStr = \"setAttr \\\"\" + $bStr +\".scaleY\\\" \"+ $scale +\";\" ;\r eval($evalStr);\r \r //then translate accordingly\r $evalStr = \"getAttr \\\"\" + $bStr +\".boundingBoxMaxY\\\";\";\r $trans = eval($evalStr);\r $evalStr = \"setAttr \\\"\" + $bStr +\".translateY\\\" \"+ ( $groundY + ($trans/2) ) +\";\" ;\r eval($evalStr);\r } \r }\r \r", object=animLocator) return 0 #camera control cam = ls(type='camera')[1] cam.attr('farClipPlane').set(10000.0) cam.setNearClipPlane(0.01) #cam.setFov(12.0) ------------------------------------------------------------------------------------------------- #city generator UI #if( window( 'City Generator', exists=True ) ): # print "window exists" # deleteUI( 'City Generator', window=True ) win = window(title="City Generator", width=250) layout = columnLayout( columnAlign=('left'), columnAttach=('both', 5), rowSpacing=10, columnWidth=250 ) radiusCtrl = floatFieldGrp( label="Radius", numberOfFields=1, value1=1000.0) radius = floatFieldGrp( radiusCtrl, query=True, value1=True) #print radius nbCtrl = intFieldGrp( label="Number of Buildings", numberOfFields=1, value1=160) numbuildings = intFieldGrp( nbCtrl, query=True, value1=True) minHCtrl = floatFieldGrp( label="Min. Height of Each Building", numberOfFields=1, value1=40.0) minH = floatFieldGrp( minHCtrl, query=True, value1=True) maxHCtrl = floatFieldGrp( label="Max. Height of Each Building", numberOfFields=1, value1=200.0) maxH = floatFieldGrp( maxHCtrl, query=True, value1=True) minWCtrl = floatFieldGrp( label="Min. Width of Each Building", numberOfFields=1, value1=40.0) minW = floatFieldGrp( minWCtrl, query=True, value1=True) maxWCtrl = floatFieldGrp( label="Max. Width of Each Building", numberOfFields=1, value1=100.0) maxW = floatFieldGrp( maxWCtrl, query=True, value1=True) minDCtrl = floatFieldGrp( label="Min. Depth of Each Building", numberOfFields=1, value1=20.0) minD = floatFieldGrp( minDCtrl, query=True, value1=True) maxDCtrl = floatFieldGrp( label="Max. Depth of Each Building", numberOfFields=1, value1=50.0) maxD = floatFieldGrp( maxDCtrl, query=True, value1=True) #print radius btn = button( label="Generate", parent=layout, command = lambda *args: generate(radius, numbuildings, minH, maxH, minW, maxW, minD, maxD) ) win.show()