Wave simulation
Download Houdini Project File (46K)
This was a project I completed for my Computer Animation and Simulation class during my last semester at USC. Going into this project, I did knew neither Python nor Houdini, and I had never attempted an implementation of Perlin Noise before. This took about 2.5 weeks to complete. Source code below:
import random
import math
import hou
NUM_GRIDPTS = 1024
sqrt_gridpts = int(math.sqrt(NUM_GRIDPTS))
lastIterationTime = 0.0
maxTimes = [0.001, 0.101, 0.501, 1.801, 4.001]
scales = [0.001, 0.071, 0.301, 1.001, 4.001]
currentTimes = maxTimes[:]
NUM_OCTAVES = len(maxTimes)-1
points = [0.0]*NUM_GRIDPTS #current point
endPoints = [[0.0]*NUM_GRIDPTS for x in xrange(NUM_OCTAVES+1)] #target point
startPoints = [[0.0]*NUM_GRIDPTS for x in xrange(NUM_OCTAVES+1)] #last target point
#seed the rng with pointNum and time
def doRandomSeed(pointNum):
x = pointNum % sqrt_gridpts
z = pointNum / sqrt_gridpts
t = hou.time()
random.seed(x*x*x + z*z + t)
#lerps points to endPoints
def interpolatePoints():
index = 0
fractions = [0.0]*(NUM_OCTAVES+1)
for time in range (1, NUM_OCTAVES+1):
fractions[time] = currentTimes[time] / maxTimes[time]
for p in points:
for o in range(1, NUM_OCTAVES+1):
points[index] += interpolate(startPoints[o][index], endPoints[o][index], fractions[o])
index += 1
#computes endPoints in a given octave
def computeOctave(octNum):
startPoints[octNum] = endPoints[octNum][:]
invFreq = pow(2, octNum)
x = invFreq / 2
z = invFreq / 2
index = z*sqrt_gridpts + x
while(index < NUM_GRIDPTS):
doRandomSeed(index)
endPoints[octNum][index] = (random.random()-0.5) * scales[octNum]
x += invFreq #increment index
if x >= sqrt_gridpts:
x = invFreq / 2
z += invFreq
index = z*sqrt_gridpts + x
computeMidpts(octNum, invFreq)
#interpolates pts between control pts
def computeMidpts(octNum, invFreq):
brX = invFreq / 2 #bottom-right point
brZ = invFreq / 2
tlX = sqrt_gridpts - invFreq / 2 #top-left point
tlZ = sqrt_gridpts - invFreq / 2
while(1):
x = tlX
z = tlZ
br = brZ*sqrt_gridpts + brX
bl = brZ*sqrt_gridpts + tlX
tr = tlZ*sqrt_gridpts + brX
tl = tlZ*sqrt_gridpts + tlX
while(x != brX or z != brZ):
if ((x != brX or z != tlZ) and
(x != tlX or z != brZ) and
(x != tlX or z != tlZ)):
#find distance between current x/z and endpts
xt = x-tlX
zt = z-tlZ
maxX = brX-tlX
maxZ = brZ-tlZ
if(xt < 0):
xt += sqrt_gridpts
if(zt < 0):
zt += sqrt_gridpts
if(maxX < 0):
maxX += sqrt_gridpts
if(maxZ < 0):
maxZ += sqrt_gridpts
xt /= float(maxX)
zt /= float(maxZ)
#bi-interp, add to endpts
b = binterpolate(endPoints[octNum][br],
endPoints[octNum][bl],
endPoints[octNum][tr],
endPoints[octNum][tl],
xt, zt)
#if(x == brX or x == tlX or z == brZ or z == tlZ):
# b /= 2.0
endPoints[octNum][z*sqrt_gridpts + x] = b #endif
#increase x and z
if(x == brX):
x = tlX
z += 1
z %= sqrt_gridpts
else:
x += 1
x %= sqrt_gridpts#endwhile
#move to next patch
if(brX == brZ and brZ == sqrt_gridpts - invFreq/2):
break
tlX = brX
if(brX == sqrt_gridpts - invFreq/2):
brX = invFreq/2
tlZ = brZ
brZ += invFreq
else:
brX += invFreq
brX %= sqrt_gridpts
#lerp for now
def interpolate(x1, x2, t):
ts = (1 - math.cos(t*math.pi))*0.5
return x1*(1-ts) + x2*ts
#2d interpolation
def binterpolate(br, bl, tr, tl, xt, yt):
interpL = interpolate(tl, bl, yt)
interpR = interpolate(tr, br, yt)
return interpolate(interpL, interpR, xt)
#called on every point
def mainLoop(pointNum):
global lastIterationTime, NUM_GRIDPTS, points, endPoints, startPoints, currentTimes
if pointNum == 0: #new iteration
if(hou.time() < lastIterationTime): #did frame counter reset?
lastIterationTime = hou.time()
for t in range(1, NUM_OCTAVES+1): #add dT
currentTimes[t] += (hou.time() - lastIterationTime)
lastIterationTime = hou.time()
for t in range(1, NUM_OCTAVES+1):
if(currentTimes[t] >= maxTimes[t]):
computeOctave(t)
currentTimes[t] = 0.0
points = [0.0]*NUM_GRIDPTS
interpolatePoints()
return points[pointNum]