Skip to content

Instantly share code, notes, and snippets.

@hexmoire
Created October 11, 2015 17:56
Show Gist options
  • Save hexmoire/a5e7c3740fa33034a173 to your computer and use it in GitHub Desktop.
Save hexmoire/a5e7c3740fa33034a173 to your computer and use it in GitHub Desktop.
a basic simulation of droplets in processing
/*
*
* droplets 1
*
* coded in Processing 2.2.1 IDE
* i appreciate a mention/link back in derivative works
*
* hexmoire / michael mcknight
* http://hexmoire.tumblr.com/
*
* this is updated code with a few bugfixes
* the original version generated the gif at:
* http://hexmoire.tumblr.com/post/130642524324/droplets-1
*
*/
//declare globals.
ArrayList<Droplet> droplets;
int dropletsPerFrame;
float dropletMinR;
float dropletMaxR;
float frameCap;
float spawnCap;
boolean exporting;
//once and only once. (hi daniel shiffman!)
void setup(){
//change the size all you want, the sketch will scale to height.
size (540,540,P3D);
//this code ripped from the processing documentation and then modified a bit.
//change "view" to alter the focal length of the camera without changing the visible
//bounds at z=0.
float view=PI/6;
float cZ=height/2. / tan(view/2);
beginCamera();
camera(0, 0, cZ, 0, 0, 0, 0, 1, 0);
perspective(view, width/(float)height,cZ/10,cZ*10);
scale (height/100.);
endCamera();
//instantiate/initialize the globals.
droplets = new ArrayList<Droplet>();
//edit these initial values to make interesting things happen.
dropletsPerFrame=3000;
dropletMinR=.2;
dropletMaxR=.5;
frameCap=60;
//spawnCap is not what it sounds like - it's the frame when spawning new droplets stops.
spawnCap=45;
//setting exporting to true will spit out a gif of every frame
exporting=false;
//get ready to draw a whole bunch of spheres the same way every time.
noStroke();
fill(255);
}
//over and over and over again. (hello again, mr. shiffman.)
void draw(){
//clear screen,
background(0);
//spawn some droplets
if(frameCount<spawnCap){
for(int k=0;k<dropletsPerFrame;k++){
//place a significant portion beyond screen boundary to ensure some
//interaction and causation out of view.
droplets.add(new Droplet(new PVector(
random(-70,70)*width/height,
random(-70,70),0),
random(dropletMinR,dropletMaxR)
));
}
}
//merge any droplets that touch.
for(int i=droplets.size()-1;i>=0;i--){
for(int j=i-1;j>=0;j--){
Droplet di=droplets.get(i);
Droplet dj=droplets.get(j);
if(dj.intersect(di)){
dj.absorb(di);
droplets.remove(i);
//goofy index math to keep intersection checks moving through the list
//without skipping or double checking. there will be missed intersections when
//droplet j grows to intersect a particle it was already checked against.
//it will be taken care of next frame.
i--;
j=i;
}
}
}
//if no longer spawning, remove a group of droplets.
//group size is linear progress towards zero droplets in last frame.
if(frameCount>=spawnCap){
int c=(int)(droplets.size()/(frameCap+1-frameCount));
c=min(c,droplets.size());
for (int i=0;i<c;i++){
droplets.remove(0);
}
}
//draw the droplets as spheres.
for(int i=droplets.size()-1;i>=0;i--){
Droplet d=droplets.get(i);
pushMatrix();
translate(d.pos.x,d.pos.y,d.pos.z);
sphere(d.r);
popMatrix();
}
//save frame if exporting.
if(exporting) {
saveFrame("frames/frame"+nf(frameCount,3)+".gif");
}
//quit at frameCap.
if(frameCount==frameCap) exit();
}
//the droplet itself.
class Droplet{
//it would be trivial to add velocity.
protected PVector pos;
protected float v;
protected float r;
//constructor - maybe it would be better to set volume than radius, depending on the application.
Droplet(PVector _pos, float _r){
pos = _pos;
setR(_r);
}
//set radius and update volume.
void setR(float _r){
r=_r;
v=4./3*PI*pow(r,3);
}
//set volume and update radius.
void setV(float _v){
v=_v;
r=pow(v/(4./3*PI),1./3);
}
//check for intersection, return boolean.
public boolean intersect(Droplet d){
return ( pos.dist(d.pos) < r+d.r );
}
//absorb a droplet
public void absorb(Droplet d){
//use PVector lerp to move surviving drop to center of mass.
pos.lerp ( d.pos , d.v / (v+d.v) );
//set new volume
setV ( v+d.v );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment