
Like Sierpinski's gasket, the Menger Sponge pattern is a pattern that will repeat infintiely in
3 Dimensions. However, the Menger pattern differs in it's code as it uses recursion to create rectangles
that fit infinitely into a predefined rectangular shape.


This simulation, inspired by LEGO, was created in Houdini by generating instances of the geometry based
on time.



The menger pattern used objects to define seperate instances of the shape. The creation of the Class was created in a seperate .py file, and then
called with another. 
The script used to define the Class Menger with it's variables and procedures: class Menger2D: def __init__(self, rect, depth): self.bbox = rect self.data = [] self.divide(rect,depth) #_______________________________________________________ # A recursive proc that subdivides a rectangle into # 9 subrects. Each time the proc is called the arg # "depth" is decremented. Recursion terminates when its # value becomes zero. def divide(self, rect, depth): if depth == 0: self.data.append(rect) return x0,y0,z0, x1,y1,z1 = rect w = float(x1  x0)/3 h = float(y1  y0)/3 d = float(z1  z0)/3 x,y,z = x0,y0,z0 rects = [] x = x0 for rows in range(3): rects.extend(self.column(x,y,z,w,h,d)) x = x + w rects = self.delete(rects) # Recursion________________ for rect in rects: self.divide(rect, depth  1) return #_______________________________________________________ def delete(self, rects): hole = rects.pop(4) return rects #_______________________________________________________ # Given the minimum x,z and maximum x,z coordinates # of a rectangle this proc returns the coordinates # of a "row" of three subrectangles. def column(self, x,y,z, w,h,d): #x,y,z = x0,y0,z0 X,Y,Z = x + w, y + h, z + d rects = [] for n in range(3): rect = [x,y,z, X,Y,Z] rects.append(rect) z,Z = z + d, Z + d return rects if __name__ == '__main__': bounds = [1,0,1, 1,0,1] menger = Menger2D(bounds,3) 
The script used to create the class into a .mel file for implementation in Maya: #Menger2D_mel.py import math import random from menger_2b import Menger2D class Menger2DMel(Menger2D): #constructor def __init__(self, box, depth, path): #base class constructor Menger2D.__init__(self, box, depth) self.path = path self.write() def write(self): """This method writes the data generatec by the base class as a mel script containing polyPlane mel commands. """ f = open(self.path, 'w') for box in self.data: rotx = 0 roty = 0 rotz = 0 x, y, z, X, Y, Z = box w = X  x h = Z  z d = Y y f.write('polyCube h %1.3f d %1.3f w %1.3f;\n' % (h,d,w)) f.write('rotate %1.3f %1.3f %1.3f;\n' % (rotx, roty, rotz)) f.write('move x %1.3f y %1.3f z %1.3f;\n' % (x, y, z)) f.close if __name__ == '__main__': bounds = [1, 1, 1, 1, 1, 1] menger = Menger2DMel(bounds, 1, '/home/eoverf20/mount/stuhome/tech312/python/Menger/menger.mel') 



By adding another for loop, we can create a third dimension to the Menger pattern. This becomes the 'layer' which in turn have 'rows'. The other difference from a 2D to a 3D object is deleting the correct sequence of cubes. To create the Menger, items 22, 16, 14, 13, 12, 10, and 4 in the sequence are deleted. For the 3D menger, the code creates a rib archive that can be called upon by Renderman at rendertime. 
boxes = [] for layer in range(3): x = x0 for rows in range(3): boxes.extend(self.row(x,y,z,w,h,d)) x = x + w y = y + h boxes = self.delete(boxes) # Recursion________________ for box in boxes: self.divide(box, depth  1) return boxes #_______________________________________________________ # Uses the indices in the holeLUT to remove specific cubes # from the list of 27 cubes in the "boxes" arg. def delete(self, boxes): for n in range(len(self.holes)): hole = boxes.pop(self.holes[n]) self.deleted.append(hole) return boxes 


#======================================================= if __name__=="__main__": bounds = [1,0,1, 1,2,1] holeList= [] numHoles = random.randrange(25) for n in range(numHoles): newRandom = random.randrange(25) holeList.append(newRandom) holeList.sort(reverse=True) defaultHoles = [22,16,14,13,12,10,4] menger = Menger3DRib(holeList, bounds, 3, '/home/eoverf20/mount/stuhome/tech312/python/Menger/code_given/test3.rib') menger.write() 
By changing the list of deleted boxes, we can create a large variety of different shapes. We can manually
change the list to create a new shape, but I used the random function within python to determine the
new sequence of deleted boxes. Before creating the rib file, the code randomly chooses how many out of a set of
25 boxes to delete and which ones. The list must be sorted from highest to lowest so that the value of the list will
still exist as the preceding boxes are deleted. 

Python can also be implemented in Houdini by creating a custom node. In order to do this, we must first create a .otl
file within a Houdini scene.







Using python for the first time, I realize that even though the syntax of this programming language seems more simplified
than mel, it's potentially much more powerful. It also has the capability to interact with other languages and a much larger
selections of programs than mel. Although using this code with a socket connection into Maya wasn't complicated, I think I prefer to use python with Houdini because it is a more flexible software with more immediate results. While Maya has to reinterpret python commands into mel (at least somewhat), Houdini is a much more direct way of executing commands.
