class Particle {
PVector position;
PVector velocity;
int timer;
Particle (float x, float y) {
position = new PVector(x, y);
// velocity = new PVector();
velocity = new PVector(0.01 - random(0.02), 0.01 - random(0.02));
timer = int(random(120));
}
void Update() {
int cellX = int(position.x);
int cellY = int(position.y);
flow[cellX][cellY].x = flow[cellX][cellY].x * 0.95 + velocity.x * 0.05;
flow[cellX][cellY].y = flow[cellX][cellY].y * 0.95 + velocity.y * 0.05;
density[cellX][cellY] += 0.1;
flow[cellX][cellY].limit(1);
velocity.x += 0.2 * flow[cellX][cellY].x;
velocity.y += 0.2 * flow[cellX][cellY].y;
//velocity.y += 0.01 * wind[cellY];
velocity.mult(0.9);
position.x = (position.x + velocity.x + resolutionX) % resolutionX;
position.y = (position.y + velocity.y + resolutionY) % resolutionY;
timer ++;
if (timer > 240) {
timer = int(random(120));
position = new PVector(random(resolutionX),
random(resolutionY));
velocity = new PVector(-1 + random(2), -1 + random(2));
}
}
void Draw(float zoom) {
stroke(0, min(255, int(255 * abs(velocity.x) / 0.2)),
min(255, int(255 * abs(velocity.y / 0.2))));
line(zoom * position.x, zoom * position.y,
zoom * (position.x + velocity.x),
zoom * (position.y + velocity.y));
}
}
int resolutionX = 192;
int resolutionY = resolutionX / 2;
PVector flow[][] = new PVector[resolutionX][resolutionY];
float density[][] = new float[resolutionX][resolutionY];
float wind[] = new float[resolutionY]; // horizontal bands
int particleCount = 8192;
Particle particle[] = new Particle[particleCount];
int currentParticle;
int oldMouseX;
int oldMouseY;
void setup() {
size(960, 480);
frameRate(60);
for (int y = 0; y < resolutionY; y ++) {
wind[y] = 1 * sin(4 * PI * y / resolutionY);
for (int x = 0; x < resolutionX; x ++) {
flow[x][y] = new PVector();
//flow[x][y] = new PVector(0.2 - random(0.4), 0.2 - random(0.4));
}
}
for (int i = 0; i < particleCount; i ++) {
particle[i] = new Particle(random(resolutionX),
random(resolutionY));
}
}
void draw() {
fill(0);
rect(0, 0, width, height);
int zoom = min(width / resolutionX, height / resolutionY);
for (int y = 0; y < resolutionY; y ++) {
for (int x = 0; x < resolutionX; x ++) {
density[x][y] = 0;
}
}
// Particles?
stroke(255);
for (int i = 0; i < particleCount; i ++) {
particle[i].Update();
//particle[i].Draw(zoom);
}
noStroke();
for (int y = 0; y < resolutionY; y ++) {
for (int x = 0; x < resolutionX; x ++) {
fill(
/*min(255, int(255 * abs(flow[x][y].x) / 0.2)),
min(255, int(255 * abs(flow[x][y].y / 0.2))),*/
int(max(0, min(255, 255 * density[x][y]))));
rect(x * zoom, y * zoom, zoom, zoom);
}
}
// Randomization of flow
//flow[int(random(resolutionX))][int(random(resolutionY))]
//= new PVector(-1 + random(2), -1 + random(2));
// Painting
int cellX = mouseX / zoom;
int cellY = mouseY / zoom;
if (mousePressed) {
for (int i = 0; i < 32; i ++) {
particle[currentParticle] = new Particle(cellX, cellY);
currentParticle = (currentParticle + 1) % particleCount;
}
}
// Make mouse movement affect flow
float dX = cellX - oldMouseX;
float dY = cellY - oldMouseY;
for (int y = -8; y < 8; y ++) {
for (int x = -8; x < 8; x ++) {
flow[max(0, min(resolutionX - 1, cellX + x))]
[max(0, min(resolutionY - 1, cellY + y))].add
(new PVector(dX, dY));
}
}
oldMouseX = cellX;
oldMouseY = cellY;
}
void keyPressed() {
setup();
}
This was my second attempt at doing a fluid simulation. Like the first, it uses particles combined with a vector field. I'm happy with the way that interacting with this one feels. I'm currently trying an approach that doesn't use particles at all- I'll upload that soon.
Move the mouse to affect the vector field. Click to add particles. Press any key to reset.