Search - User list
Full Version: Generating brick wall patterns
Root » Work in Progress » Generating brick wall patterns
futo
Helloes,

I'm an AI programmer and I got interested in Houdini due to it's procedural foundation, (which is something we programmers like!), the awesome apprentice deal (the other 3d app companies should really take a hint here!) and the fact that I wanted to learn just a little bit more about modelling, rigging and rendering while I'm having a bit of a break between projects.

I have watched a lot of tutorials and have been doing various things in order to learn how everything works. One obvious thing for me wat to look into generating buildings, terrain, objects, etc. since I'm really not very artistic and there is a lot of stuff you can come up with that have fairly simple solutions (although perhaps not groundbreaking designs .

One of the things I've worked on is generating brick walls (or floors for that matter) and during the process I've been banging my head against the standard SOP's trying to figure out how to put networks together that would generate the results I was after and after several attempts I gave up and coded something up in Python instead.

I think it is simply a lack of experience with Houdini that holds me back and I'm really impressed with the imagination and tricks that people come up with, when watching tutorials and videos from the various forums, so I figured I would try to encourage people a bit here to share some ideas as to how I could have gotten the same results without coding.

Brick wall requirements

So onto the requirements. I wanted to be able to generate a grid with a brick like pattern so that the node would produce:

* A connected mesh with a group of bricks I could extrude and modify in a network to add detail to the bricks
* Brick alignment should be minimized (i.e. gaps should be offset in adjacent rows)
* Variable brick width should be supported
* The mesh should contain as few polygons as possible and it should be all triangles or quads

My solution

The attached image show some of the patterns my SOP can produce and I've attached the otl as well, but if you can't be bothered to install it, the full listing is included in the post as well.

As a bit of discussion of the problems I ran into when trying to do this with standard SOP's, my main problems where:

* Ensuring that the grid is connected. In particular I struggled with figuring out how to fuse points with edges. Cookie is generally pretty unstable and it more or less randomly removes points (or at least so it felt) and fuse only fuse points

* Avoiding brick alignment. With a random brick size I couldn't figure out how to avoid that gaps would align (which looks unnatural and I guess would indicate bad masonry?).

* Keeping the mesh optimal. With the solutions I tried it was hard to control how the mesh would end up looking in terms of poly count (with the constraint that everything should be triangles or quads). In my solution the only points are the corners of the bricks and while it might not be ideal for adding detail I couldn't come up with a way to reduce the number of polygons in the resulting wall.

The solution could do with a lot of refinement for better control of the mesh, how bricks are laid out, but I think the biggest problem with the solution is the way the padding between the bricks are skinned. The reason for this solution was that it was simple to code, but if I want to move to walls that can bend I guess I would need to change this to something that would have better normals (i.e. better symmetry) but I'm kinda a noob when it comes to polygonal modelling so this is all something I learn along the way

Code listing
# =============================================================================
# Purpose: SOP for generating a brick like pattern


from random import seed
from random import random


# —————————————————————————–
# Global variables


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

wallWidth = hou.ch(“wall_sizex”)
wallHeight = hou.ch(“wall_sizey”)

randomSeed = hou.ch(“seed”)
brickHeight = hou.ch(“brick_sizey”)
brickWidth = hou.ch(“brick_sizex”)
brickWidthVariation = hou.ch(“brick_width_variation”)
brickPadding = hou.ch(“brick_padding”)
brickOffset = hou.ch(“brick_offset”)
minBrickWidth = hou.ch(“brick_minWidth”)


# —————————————————————————–
# Math helper functions


seed(randomSeed)


def clamp(value, minimum, maximum):
return min(max(value, minimum), maximum)


def fit01(value, rangeMin, rangeMax):
return value * (rangeMax - rangeMin) + rangeMin


# —————————————————————————–
# Type definitions


class Brick:
def __init__(self, x, y, width, height):
self.x1 = x
self.x2 = x + width
self.y1 = y
self.y2 = y + height


# —————————————————————————–
# Build wall definition


def buildWall(x1, y1, x2, y2):

wall =

y = y1
while y < y2:
brickLine =
x = x1
height = brickHeight

if len(wall) > 0:
pidx = 0
prevLine = wall

while x < x2:
width = brickWidth + fit01(random(), -brickWidthVariation, brickWidthVariation)

if x2 - (x + width) < minBrickWidth:
# Extend end stone
width = x2 - x
elif len(wall) > 0:
# Prevent brick alignment
while pidx < len(prevLine) and prevLine.x2 < x:
pidx += 1

tpidx = pidx
while tpidx < len(prevLine) and prevLine.x2 < x + width + brickOffset:
diff = x + width - prevLine.x2
if diff > 0 and diff < brickOffset:
width += brickOffset - diff
elif diff > -brickOffset and diff <= 0:
width -= brickOffset + diff
tpidx += 1

width = clamp(width, minBrickWidth, x2 - x)
brick = Brick(x, y, width, height)
brickLine.append(brick)

x += width + brickPadding

wall.append(brickLine)
y += height + brickPadding

return wall


# —————————————————————————–
# Build geometry


def addPoint(x, y, z):
p = geo.createPoint()
p.setPosition((x,y,z))
return p


def addPolygon(points):
poly = geo.createPolygon()
for point in points:
poly.addVertex(point)


def buildGeometry(wall):
brickGroup = geo.createPrimGroup(“bricks”)

Y = len(wall)
for y in range(0, Y):
brickLine = wall

X = len(brickLine)
for x in range(0, X):
brick = brickLine

# Brick geometry
brick.points = [
addPoint(brick.x1, brick.y1, 0),
addPoint(brick.x2, brick.y1, 0),
addPoint(brick.x2, brick.y2, 0),
addPoint(brick.x1, brick.y2, 0)
]

poly = geo.createPolygon()
for point in brick.points:
poly.addVertex(point)

brickGroup.add(poly)

# vertical padding geometry
if x > 0:
points = [ prevBrick.points, brick.points, brick.points, prevBrick.points ]
addPolygon(points)

prevBrick = brick

# horizontal padding geometry
if y > 0:
upperLine = wall
lowerLine = wall

UX = len(upperLine)
LX = len(lowerLine)

uidx = 0
lidx = 0

while uidx < UX and lidx < LX:
upperBrick = upperLine
lowerBrick = lowerLine

if lowerBrick.x2 < upperBrick.x2:
points = [ upperBrick.points, lowerBrick.points, lowerBrick.points ]
if lidx + 1 < LX:
points.append(lowerLine.points)
else:
points.append(upperBrick.points)
lidx += 1
else:
points = [ upperBrick.points, upperBrick.points, lowerBrick.points ]
if uidx + 1 < UX:
points.append(upperLine.points)
else:
points.append(lowerBrick.points)
uidx += 1

poly = geo.createPolygon()
for point in points:
poly.addVertex(point)



# —————————————————————————–
# Main


wall = buildWall(0, 0, wallWidth, wallHeight)
buildGeometry(wall)
iseefishpeople
dont know if it will help you, but i wrote a loop ages ago that used pure python to output a house including roof for a house logo project i was working on at the time, see attached ;0)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB