• fullscreen
  • PerlinNoise.pde
  • attractor.pde
  • field.pde
  • noc_fluid_flowfield2.pde
  • thingy.pde
  • double Interpolate(double x, double y, double a)
    {
        double val = (1 - cos((float)a * PI)) * .5;
        return x * (1 - val) + y * val;
    }
    
    double Noise(int x, int y)
    {
        int n = x + y * 57;
        n = (n<<13) ^ n;
    
        return ( 1.0 - ( (int)(n * (n * n * r1 + r2) + r3) & 0x7fffffff) / 1073741824.0);
    }
    
    double Smooth(double x, double y)
    {
        double n1 = Noise((int)x, (int)y);
        double n2 = Noise((int)x + 1, (int)y);
        double n3 = Noise((int)x, (int)y + 1);
        double n4 = Noise((int)x + 1, (int)y + 1);
    
        double i1 = Interpolate(n1, n2, x - (int)x);
        double i2 = Interpolate(n3, n4, x - (int)x);
    
        return Interpolate(i1, i2, y - (int)y);
    }
    
    
    float PerlinNoise2d(int x, int y)
    {
        double total = 0.0;
    
    		double cloud_frequency = global_cloud_frequency;    // USER ADJUSTABLE
    		double cloud_persistence = global_cloud_persistence;   // USER ADJUSTABLE
    		double cloud_octaves = global_cloud_octaves;         // USER ADJUSTABLE
    		double cloud_amplitude = global_cloud_amplitude;       // USER ADJUSTABLE
    		double cloud_coverage = global_cloud_coverage;   // USER ADJUSTABLE
    		double cloud_density = global_cloud_density;    // USER ADJUSTABLE
    		
    		
    		//println(global_cloud_frequency + "/" + cloud_frequency);
    
    
        for(int lcv = 0; lcv < cloud_octaves; lcv++)
        {
            total = total + Smooth(x * cloud_frequency, y * cloud_frequency) * cloud_amplitude;
            cloud_frequency = cloud_frequency * 2;
            cloud_amplitude = cloud_amplitude * cloud_persistence;
        }
    
        total = (total + cloud_coverage) * cloud_density;
    
        if(total < 0) total = 0.0;
        if(total > 1) total = 1.0;
    
        return (float)total;
    }
    
    class Attractor
    {
    	float pnoise;
    	float strength;
    	
    	Attractor(float pnoise, float strength)
    	{
    		this.pnoise = pnoise;
    		this.strength = strength * 8;
    	}
    	
    	PVector getForce()
    	{
    		float theta = map(pnoise, minf, maxf, 0,TWO_PI);
    		return new PVector(strength * cos(theta), strength * sin(theta));
    	}
    	
    }
    
    class WorldField
    {
    	ArrayList things;
    	
    	WorldField()
    	{
    		things = new ArrayList();
    	}
    	
    	public void addThings(int num)
    	{
    		for (int i = 0; i < num ; i++)
    		{
    			things.add(new Thingy(new PVector(random(0,width),random(0,height))));
    		}
    	}
    	
    	public void addThing(Thingy th)
    	{
    		things.add(th);
    	}
    	
    	public void update(Attractor[][] hiddenfield)
    	{
    		for (int i = 0; i < things.size() ; i++)
    		{
    			Thingy t = (Thingy)things.get(i);
    			
    			if (t.dead)
    			{
    				t.loc = new PVector(random(width),random(height),random(0,1) * -2);
    				t.live();				
    			}
    			else
    			{
    				
    				//mouse position
    				
    				
    				PVector force = PVector.sub(t.loc, new PVector(mouseX,mouseY,-10));	
    				
    				PVector dis = force.get();
    				dis.z = 0;
    				
    				float d = dis.mag();
    				
    				if (d < 2)
    				{
    					d = 2;
    				}
    				
    				force.mult(8000.0 / sq(d));			
    				t.applyForce(force);
    				
    				//check the flowfield
    				
    				int xx = constrain( int(t.loc.x) , 0 , width )/ spacing;
    				int yy = constrain ( int(t.loc.y) , 0 , height )/ spacing;
    				
    				if (fieldUpdated[xx][yy] == false)
    				{
    					float f = PerlinNoise2d(int(xx + global_offset_x),int(yy + global_offset_y));
    
    					flowField[xx][yy] = new Attractor(f, 5);
    					fieldUpdated[xx][yy] = true;
    				}
    				
    				
    				PVector force_field = hiddenfield[ xx ][ yy ].getForce();
    				force_field.z = 0.2;
    				
    				//println(force.x + "," + force.y + "," + force.z);
    				t.applyForce(force_field.get());
    						
    				t.update();
    			}
    		}
    	}
    	
    	public void display()
    	{
    		for (int i = 0; i < things.size() ; i++)
    		{
    			Thingy t = (Thingy)things.get(i);
    			t.display();
    		}
    	}
    }
    
    Attractor [][]flowField;
    boolean [][]fieldUpdated;
    
    WorldField world;
    
    float global_cloud_frequency;    // USER ADJUSTABLE
    float global_cloud_persistence;   // USER ADJUSTABLE
    float global_cloud_octaves;         // USER ADJUSTABLE
    float global_cloud_amplitude;       // USER ADJUSTABLE
    float global_cloud_coverage;   // USER ADJUSTABLE
    float global_cloud_density;    // USER ADJUSTABLE
    
    double r1 = 1000 + random(9000);
    double r2 = 100000 + random(900000);
    double r3 = 1000000000 + random(1000000000);
    
    int spacing = 40;
    int refreshThreshold = 120;
    
    float global_offset_x;
    float global_offset_y;
    
    float minf = 20;
    float maxf = 0;
    
    color colorSmoke;
    
    void resetFlowField()
    {
    	global_cloud_frequency = 0.1;    // USER ADJUSTABLE
    	global_cloud_persistence = 0.2;   // USER ADJUSTABLE
    	global_cloud_octaves = 5;         // USER ADJUSTABLE
    	global_cloud_amplitude = 0.00001;       // USER ADJUSTABLE
    	global_cloud_coverage = 0.04;   // USER ADJUSTABLE
    	global_cloud_density = 0.01;    // USER ADJUSTABLE
    
    	global_offset_x = random(1000,10000);
    	global_offset_y = random(1000,10000);
    
    	flowField = new Attractor[width][height];		
    	fieldUpdated = new boolean[width][height];
    
    	minf = 20;
    	maxf = 0;
    
    	for (int i = 0; i < height ; i++)
    	{
    		for (int j = 0; j < width ; j++)
    		{
    			float q = 1;//random(10000);
    			float f = PerlinNoise2d(int(j * q + global_offset_x),int(i * q + global_offset_y));
    
    			if (f > maxf)
    			{
    				maxf = f;
    			}
    			if (f < minf)
    			{
    				minf = f;
    			}
    
    			//print(f + ",");
    			flowField[j][i] = new Attractor(f, 5);
    			fieldUpdated[j][i] = true;
    		}
    	}
    
    
    	println(minf + ", " + maxf);
    
    	resetColor();
    }
    void resetColor()
    {
    	colorMode(HSB,360,100,100,100);
    
    	background(random(360),random(100),random(0,15));
    	colorSmoke = color(random(360),random(70,100),random(70,100));
    
    	colorMode(RGB,255,255,255,100);
    }
    void setup() {
    
    	size(800,450);
    	smooth();
    
    
    	world = new WorldField();
    
    	resetFlowField();
    
    	for (int i = 0; i < height/spacing ; i++)
    	{
    		for (int j = 0; j < width/spacing ; j++)
    		{
    			Thingy t = new Thingy(new PVector(j * spacing + spacing/2, i * spacing + spacing/2,random(0,1) * -1));
    			world.addThing(t);
    		}
    	}
    }
    
    
    void draw() {
    	background(0);
    	world.update(flowField);
    	world.display();
    
    	if (frameCount >= refreshThreshold && (frameCount % refreshThreshold == 0))
    	{
    		updateField();
    	}
    
    
    }
    
    void updateField()
    {
    	for (int i = 0; i < width ; i++)
    	{
    		for (int j = 0; j < height ; j++)
    		{
    			fieldUpdated[i][j] = false;
    		}
    	}
    
    	global_offset_x = random(1000,10000);
    	global_offset_y = random(1000,10000);
    	//println("field updated");
    }
    
    void keyPressed()
    {
    	if (key == ' ')
    	{
    		updateField();
    		//resetFlowField();
    		//println("reset");
    	}
    	
    	if (key == 'c')
    	{
    		resetColor();
    	}
    
    	if (key == 'p')
    	{
    		saveFrame("########.tif");
    	}
    
    }
    
    class Thingy
    {
    	private PVector last_loc;
    	public PVector loc;
    	public PVector acc;
    	public PVector vel;
    	public float mass;
    	
    	public boolean dead = false;
    	
    	float grayscale = 0;
    	float age = 0;
    	
    	Thingy()
    	{
    		this.acc = new PVector(0,0);
    		this.vel = new PVector(0,0);
    		this.loc = new PVector(0,0);
    		this.last_loc = new PVector(0,0);
    		this.mass = 0;
    	}
    	
    	
    	Thingy(PVector initial_loc)
    	{
    		
    		this.acc = new PVector(0,0);
    		
    		float theta = random(0,TWO_PI);
    		
    		this.vel = new PVector(0,0);//new PVector(random(1,3) * cos(theta),random(1,3) * sin(theta));
    		this.loc = initial_loc.get();
    		this.last_loc = initial_loc.get();
    		this.mass = random(0,1) * 1000 + 700;
    		//println("mass:" + this.mass);
    		this.grayscale = 255;//map(random(1,5),1,5,0,255);
    		
    	}
    	
    	public void die()
    	{
    		dead = true;
    	}
    	
    	public void live()
    	{
    		this.last_loc = this.loc.get();
    		dead = false;
    		age = 0;
    	}
    	
    	void applyForce(PVector force)
    	{
    		force.div(this.mass);
    		this.acc.add(force);
    	}
    	
    	void update()
    	{
    		if (this.loc.x > width || this.loc.x < 0 || this.loc.y > height || this.loc.y < 0)
    		{
    			die();
    		}
    		else
    		{
    			this.last_loc = this.loc.get();
    			
    			this.vel.add(this.acc);
    			this.loc.add(this.vel);
    			
    
    			this.vel.mult(0.98);
    			this.age++;
    		}
    
    	}
    	
    	void display()
    	{
    		if (!dead)
    		{
    			strokeWeight( constrain(map(this.loc.z,-1,8,0.5,0.8),0,1.2));
    			stroke(colorSmoke,(this.loc.z + 15) * 3 );//(map(this.loc.z,-1,200,30,255));//
    			
    			noFill();
    			
    			float side = constrain(map(this.loc.z,-1,3,2,4),2,4);
    			line(this.loc.x - side,this.loc.y,this.loc.x + side,this.loc.y);
    			line(this.loc.x,this.loc.y - side,this.loc.x,this.loc.y + side);
    			this.last_loc = this.loc.get();
    
    			this.acc.mult(0);
    		}
    	}
    	
    }
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Liangjie Xia

    fluid pluses in flow field

    Add to Faves Me Likey@! 5
    You must login/register to add this sketch to your favorites.

    i updated the fluid sketch a little bit.

    originally i wanted to create something to replicate the fluid effect on http://rhizomatiks.com/ (it's on their home page and it's randomly shown so do refresh)

    Hey did you try getting the plus leave trails? some kind of bezier curve?
    Todd Pashak
    26 Feb 2009
    very lovely!
    Liangjie Xia
    27 Feb 2009
    sounds interesting! haven't thought about making trails yet. so far this is more like a concept proof of the motion to me. will try to see if i can do it! a lot of foreseeable param tweaking though...
    You need to login/register to comment.