• fullscreen
  • PerlinNoise.pde
  • attractor.pde
  • field.pde
  • noc_fluid_flowfield.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 * 100;
    	}
    	
    	PVector getForce()
    	{
    		float theta = map(pnoise, minf, maxf, 0,TWO_PI) + global_offset_theta;
    		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
    			{
    				
    				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;
    color colorSmoke;
    
    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 = 15;
    int refreshFrameCount = 300;
    
    float global_offset_x;
    float global_offset_y;
    float global_offset_theta;
    
    float minf = 20;
    float maxf = 0;
    
    void resetFlowField()
    {
    	global_cloud_frequency = 0.08;    // USER ADJUSTABLE
    	global_cloud_persistence = 0.2;   // USER ADJUSTABLE
    	global_cloud_octaves = 12;         // USER ADJUSTABLE
    	global_cloud_amplitude = 0.00001;       // USER ADJUSTABLE
    	global_cloud_coverage = 0.09;   // USER ADJUSTABLE
    	global_cloud_density = 0.01;    // USER ADJUSTABLE
    
    	global_offset_x = random(1000,10000);
    	global_offset_y = random(1000,10000);
    	global_offset_theta = random(0,PI / 2);
    
    	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, 10);
    			fieldUpdated[j][i] = true;
    		}
    	}
    	
    	
    	println(minf + ", " + maxf);
    	
    	resetColor();
    }
    
    void setup() {
    
    	size(800,450);
    	smooth();
    	resetBg();
    	resetColor();
    
    	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(255,1);
    	world.update(flowField);
    	world.display();
    	
    	if (frameCount >= refreshFrameCount && (frameCount % refreshFrameCount == 0))
    	{
    		resetField();
    	}
    }
    
    void resetField()
    {
    	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);
    	global_offset_theta = random(0,PI / 2);
    	println("field updated");
    }
    
    void resetColor()
    {
    	colorMode(HSB,360,100,100,100);
    
    	colorSmoke = color(random(360),random(70,100),random(70,100));
    
    	colorMode(RGB,255,255,255,100);
    }
    
    void resetBg()
    {
    	colorMode(HSB,360,100,100,100);
    	background(random(360),random(100),random(0,15));
    	colorMode(RGB,255,255,255,100);
    }
    
    void keyPressed()
    {
    	if (key == ' ')
    	{
    		resetBg();
    		resetField();
    	}
    	
    	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(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.95);
    			this.age++;
    		}
    
    	}
    	
    	void display()
    	{
    		if (!dead)
    		{
    			strokeWeight(0.15f);
    			//stroke(71,121,172,10);
    			stroke(colorSmoke,10);
    			noFill();
    			
    			line(this.loc.x,this.loc.y,this.last_loc.x,this.last_loc.y);
    
    			this.acc.mult(0);
    		}
    	}
    	
    }
    

    code

    tweaks (0)

    about this sketch

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

    license

    advertisement

    Liangjie Xia
    Matt Richard plus+
    26 Feb 2009
    Very sweet looking!
    Liangjie Xia
    27 Feb 2009
    thanks matt!
    That really encourages me to go on learning. :)
    Guigui plus+
    27 Feb 2009
    Beautiful, very subtle. A great sketch! 8^)
    Mariano Crivelli
    12 Mar 2009
    Very nice! This just makes me want to learn more about noise :p
    iek
    4 Oct 2009
    Seriously, I like it! This work can totally be a good reference to show the power of processing.
    You need to login/register to comment.