3D Menger Sponge - Part 2

Introduction

A typical cubic Menger Sponge is shown in figure 1. It is a fractal object created by recursively replacing a cube with a grid of 27 sub-cubes of which 7 are removed. Figure 2 shows four objects where the depth of recursion is 0, 1, 2 and 3.

Project Details

This project was designed to bring the Menger Sponge into a 3rd spacial dimension. Through adjusting the code and adding the holeLUT the shape expands and also removes points adding interest to the design.

 

Python Code in Houdini

node = hou.pwd()
geo = node.geometry()

# Add code to modify contents of geo.
# Use drop down menu to select examples.

import random

#Declaring Variables For Houdini
node = hou.pwd()
geo = node.geometry()  

meng = hou.node('/obj/menger')

bx = node.evalParm("width")
by = node.evalParm("height")
bz = node.evalParm("depth")
iterations = node.evalParm("iterations")
scaleP = node.evalParm("objectScale")
#rands = random.random()*node.parm("randomSeed").eval()
  
bounds = [0, 0, 0, bx, by, bz]
  
#declare the global variables  
holes = []  # list of deleted cubes
menger = [] # list of non-deleted cubes
holeLUT = [19,14,12,9,7, 0]  
#holeLUT = [22,16,14,13,12,10,4]  
  
# finds the center of the 'box' to create a point
def center(bbox):
    x,y,z,X,Y,Z = bbox
    midpnt = []
    midpnt = ((x+X)/2, (y+Y)/2, (z+Z)/2)
    return midpnt
  
#_______________________________________________________
# this proc returns the bounding box coordinates of a "row" of three boxes.
def row(x0,y0,z0, w,h,d):
    x,y,z = x0,y0,z0
    X,Y,Z = x + w, y + h, z + d
    boxes = []
  
    for n in range(3):
        box = [x,y,z, X,Y,Z]
        boxes.append(box)
        z,Z = z + d, Z + d
    return boxes
#_______________________________________________________
# Recursion begins breaking the bounding box into 27 sub divisions
def divide(bbox, depth):
    if depth == 0:
        menger.append(bbox)
        return []
    x0,y0,z0,x1,y1,z1 = bbox
    w = float(x1 - x0)/3
    h = float(y1 - y0)/3
    d = float(z1 - z0)/3
    
    x,y,z = x0,y0,z0
    boxes = []
    for layer in range(3):
        x = x0
        for rows in range(3):
            boxes.extend(row(x,y,z,w,h,d))
            x = x + w
        y = y + h
    boxes = delete(boxes)
  
    # Recursion________________
    for box in boxes:
        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(boxes):
    for n in range(len(holeLUT)):
        hole = boxes.pop(holeLUT[n])
        holes.append(hole)
    return boxes

###implement code
divide(bounds, iterations)
  
#create pscale
createpscale = geo.addAttrib(hou.attribType.Point, "pscale" , scaleP)

for box in menger:
    pt = geo.createPoint()
    pt.setPosition(center(box))
  
count = 0
for box in holes:
count += 1

Conclusion

This was a fun project, once it's implemented in its basic form there are infinite adjustments that can be added for visual interest. Using "Class" in python helps to grow and control the program making it easier to organize the logic.