Trying again.
The following should be a correct 3D conversion of Daniel Shiffman’s 2D Perlin noise flow field presented in this tutorial.
All I’m asking is:
- How to compute and apply the 3D noised angle to the particle object ?
I would really really appreciate if someone could help.
EDIT:
- I’ve stored the 3D vectors in a 2D array list as suggested in the video posted earlier.
- I’m applying the same combination of cos(), sin(), absin()
- Following the same instructions, particles are created on top of the bounding box (y = 0) and are removed if leaving the bounding box. New particles are created instead.
However, no matter what I do (playing with noiseDetail(), noiseScale, scale of the flow field…), the output is never like what’s shown in the video and barely looks like a flow field.
Again, this has to do with the computation of the 3D noise based angle.
add_library('peasycam')
def setup():
global cols, rows, layers, noiseScale, flowfield, scl, particles, b, W, H, D
hint(DISABLE_DEPTH_TEST)
size(800, 800, P3D)
frameRate(1000)
stroke('0x41a5ff')
strokeWeight(1.5)
noiseDetail(8, 4)
cam = PeasyCam(this, 900)
#Bounding Box dimensions
W, H, D = 400, 400, 400
#Bounding Box
b = createShape(BOX, W, H, D)
b.setFill(color(255, 0))
b.setStroke(color(255))
b.setStrokeWeight(.2)
particleCount = 1000
noiseScale = .1
scl = 100
cols = floor(W / scl)
rows = floor(H / scl)
layers = floor(D / scl)
#Collection of particle objects
particles = [Particle() for i in range(particleCount)]
#3D array list (1 for each dimension)
flowfield = [[[] for z in range(layers)] for i in range(cols*rows)]
#Computing fixed flow field
for x in range(rows):
for y in range(cols):
index = x + y * cols
for z in range(layers):
#Computing angle (probably not correct)
angle = noise(x *noiseScale, y *noiseScale, z* noiseScale) * TWO_PI
#Combination of cos() sin() absin() (as suggested in the video)
v = PVector(cos(angle), sin(angle), abs(sin(angle))).setMag(.7)
#Storing in 2D array list (as suggested in the video)
flowfield[index][z] = v
def draw():
background(14)
#Displaying Bounding Box
shape(b)
#Translating because of PeasyCam
pushMatrix()
translate(-W>>1, -H>>1, -D>>1)
#Running particle objects
for p in particles:
p.follow()
p.update()
p.edges()
p.render()
popMatrix()
class Particle(object):
def __init__(self):
self.location = PVector(random(W), 5, random(D)) #Particles falling from top (as suggested in the video)
self.velocity = PVector(0)
self.acceleration = PVector()
self.angle = PVector()
self.maxspeed = 4
def update(self):
self.velocity.add(self.acceleration)
self.velocity.limit(self.maxspeed)
self.location.add(self.velocity)
self.acceleration.mult(0)
def applyForce(self, force):
self.acceleration.add(force)
def follow(self):
x = floor(self.location.x / scl)
y = floor(self.location.y / scl)
z = floor(self.location.z / scl)
#Safety (for some reasons x, y or z sometimes goes out of the bounding box)
if x < cols and y < rows and z < layers:
#Applying corresponding force based on particle location
idx = x + y * cols
n = flowfield[idx][z]
self.applyForce(n)
def render(self):
point(self.location.x, self.location.y, self.location.z)
def edges(self):
#As suggested in the video:
#Removing particles from array list if outside Bounding box
#Appending new Particle() object instead
if self.location.x > W or self.location.x < 0 or self.location.y > H or self.location.y < 0 or self.location.z > D or self.location.z < 0:
del particles[particles.index(self)]
particles.append(Particle())