marchingSquaresMetaballs/marchingSquaresMetaballs.pde
2022-05-18 06:51:32 +02:00

119 lines
4.2 KiB
Plaintext

final float distMult = 40f;
final int ballAmount = 10;
final float minVelocity = 1f;
final float maxVelocity = 5f;
final float minRadius = 10f;
final float maxRadius = 50f;
final int columns = 320 + 1;
final int rows = 180 + 1;
float[][] grid;
float cellWidth, cellHeight;
Metaball[] metaballs;
void setup() {
fullScreen();
grid = new float[columns][rows];
cellWidth = (float)width / (columns-1);
cellHeight = (float)height / (rows-1);
metaballs = new Metaball[ballAmount];
for (int i = 0; i < ballAmount; i++)
metaballs[i] = new Metaball();
}
void draw() {
background(0);
// Update and display all metaballs
stroke(255);
noFill();
for (int i = 0; i < ballAmount; i++) {
Metaball current = metaballs[i];
current.position.add(current.velocity);
if (current.position.x >= width) {
current.position.x = width;
current.velocity.x *= -1;
} else if (current.position.x <= 0) {
current.position.x = 0;
current.velocity.x *= -1;
}
if (current.position.y >= height) {
current.position.y = height;
current.velocity.y *= -1;
} else if (current.position.y <= 0) {
current.position.y = 0;
current.velocity.y *= -1;
}
// PVector pos = current.position;
// float rad = current.radius;
// ellipse(pos.x, pos.y, rad*2, rad*2);
}
// Calculate value of cells in 'grid' as distance from any given metaball in 'metaballs'
for (int i = 0; i < columns; i++)
for (int j = 0; j < rows; j++) {
PVector current = new PVector(i*cellWidth, j*cellHeight);
float value = 0f;
int ballCount = 0;
for (int k = 0; k < ballAmount; k++) {
Metaball ball = metaballs[k];
// Magic trickery that i made up to convert a distance to a brightness value
float d = max(255-(float)Math.cbrt((PVector.dist(current, ball.position)-ball.radius)*distMult*1000), 0);
if (d > 0f) {
value += d;
ballCount++;
}
}
// Value should be downscaled somehow in order to not exceed the brightness of a single metaball whenever any others come too close
// value = min(255, value);
grid[i][j] = map(value, 0, 255, -1, 1);
}
// Display all cells in 'grid' with a greyscale value color
noStroke();
for (int i = 0; i < columns; i++)
for (int j = 0; j < rows; j++) {
fill(grid[i][j]*255);
rect(i*cellWidth, j*cellHeight, cellWidth, cellHeight);
}
// Display outlines for all cells. Values will be mapped from 255-0 to 1-0
stroke(255);
for (int i = 0; i < columns-1; i++)
for (int j = 0; j < rows-1; j++) {
float x = i*cellWidth;
float y = j*cellHeight;
PVector a = new PVector(x + cellWidth / 2, y );
PVector b = new PVector(x + cellWidth , y + cellHeight / 2);
PVector c = new PVector(x + cellWidth / 2, y + cellHeight );
PVector d = new PVector(x , y + cellHeight / 2);
int value = ceil(grid[i][j])*8 + ceil(grid[i+1][j])*4 + ceil(grid[i+1][j+1])*2 + ceil(grid[i][j+1]);
if (value == 1 || value == 10 || value == 14)
line(c.x, c.y, d.x, d.y);
if (value == 2 || value == 5 || value == 13)
line(b.x, b.y, c.x, c.y);
if (value == 3 || value == 12)
line(b.x, b.y, d.x, d.y);
if (value == 4 || value == 10 || value == 11)
line(a.x, a.y, b.x, b.y);
if (value == 5 || value == 7 || value == 8)
line(a.x, a.y, d.x, d.y);
if (value == 6 || value == 9)
line(a.x, a.y, c.x, c.y);
}
}
class Metaball {
PVector position, velocity;
float radius;
Metaball() {
position = new PVector(random(width), random(height));
velocity = PVector.random2D();
velocity.setMag(random(minVelocity, maxVelocity));
radius = random(minRadius, maxRadius);
}
}