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]