Nature of Code Final Project (Initial Ideas/Sketches)

Nature of Code, Flow Field-Final Project Initial Ideas from Colin Narver on Vimeo.

I am using dan's flow field example (6_4) to test the progression of triangles moving around a flow field with two obstacles, determined by brightness, dictating their path. I am interested in potentially combining this with projection mapping/kinect onto an external texture or surface where the user could dictate the flow of vectors by the way they physically move, shape or build up the environment with their hands.

// Colin Narver (Flow Field Experiments) // Flow Field Following // Via Reynolds: http://www.red3d.com/cwr/steer/FlowFollow.html //Maybe do projection mapping onto a box of sand? // Using this variable to decide whether to draw all the stuff boolean debug = true; // Flowfield object FlowField flowfield; // An ArrayList of vehicles ArrayList vehicles; PImage background; void setup() { size(600, 450, P2D); background = loadImage("Nature_of_code_shapes.jpg"); // Make a new flow field with "resolution" of 16 flowfield = new FlowField(7); //adjust this to affect resolution vehicles = new ArrayList(); // Make a whole bunch of vehicles with random maxspeed and maxforce values //for (int i = 0; i < 120; i++) { //vehicles.add(new Vehicle(new PVector(random(width), random(height)), random(2, 5), random(0.1, 0.5))); //} } void draw() { background(255); imageMode (CORNER); image(background, 0, 0); // Display the flowfield in "debug" mode if (debug) flowfield.display(); // flowfield.update(); for live data later (kinect) // Tell all the vehicles to follow the flow field for (Vehicle v : vehicles) { v.follow(flowfield); v.run(); } // Instructions fill(0); //text("Click the mouse to generate a new flow field.",10,height-20); } void keyPressed() { if (key == ' ') { debug = !debug; } } // Make a new flowfield void mousePressed() { //flowfield.init(); vehicles.add(new Vehicle(new PVector(mouseX,mouseY), random(2, 5), random(0.1, 0.5))); } void mouseDragged() { //flowfield.init(); vehicles.add(new Vehicle(new PVector(mouseX,mouseY), random(2, 5), random(0.1, 0.5))); } // The Nature of Code // Daniel Shiffman // http://natureofcode.com // Flow Field Following //what is the vehicle's desired velocity?? //arrow below triangle in flow field indicates vehicle's desired velocity class Vehicle { // The usual stuff PVector location; PVector velocity; PVector acceleration; float r; float maxforce; // Maximum steering force float maxspeed; // Maximum speed Vehicle(PVector l, float ms, float mf) { location = l.get(); r = 3.0; maxspeed = ms; maxforce = mf; acceleration = new PVector(0,0); velocity = new PVector(0,0); } public void run() { update(); borders(); display(); } // Implementing Reynolds' flow field following algorithm // http://www.red3d.com/cwr/steer/FlowFollow.html void follow(FlowField flow) { // What is the vector at that spot in the flow field? PVector desired = flow.lookup(location); // Scale it up by maxspeed desired.mult(maxspeed); // Steering is desired minus velocity PVector steer = PVector.sub(desired, velocity); steer.limit(maxforce); // Limit to maximum steering force applyForce(steer); } void applyForce(PVector force) { // We could add mass here if we want A = F / M acceleration.add(force); } // Method to update location void update() { // Update velocity velocity.add(acceleration); // Limit speed velocity.limit(maxspeed); location.add(velocity); // Reset accelertion to 0 each cycle acceleration.mult(0); } void display() { // Draw a triangle rotated in the direction of velocity float theta = velocity.heading2D() + radians(90); fill(175); stroke(0); pushMatrix(); translate(location.x,location.y); rotate(theta); beginShape(TRIANGLES); vertex(0, -r*2); vertex(-r, r*2); vertex(r, r*2); endShape(); popMatrix(); } // Wraparound void borders() { if (location.x < -r) location.x = width+r; if (location.y < -r) location.y = height+r; if (location.x > width+r) location.x = -r; if (location.y > height+r) location.y = -r; } } // Flow Field Following class FlowField { // A flow field is a two dimensional array of PVectors PVector[][] field; int cols, rows; // Columns and Rows int resolution; // How large is each "cell" of the flow field FlowField(int r) { resolution = r; // Determine the number of columns and rows based on sketch's width and height cols = width/resolution; rows = height/resolution; println(cols + " " + rows); field = new PVector[cols][rows]; init(); } //This is the section to get to understand best*** void init() { // Reseed noise so we get a new flow field every time // noiseSeed((int)random(10000)); for (int i = 0; i < cols; i++) { for (int j = 0; j < rows; j++) { int x = i*resolution; int y = j*resolution; int index = x + y * background.width; color c = background.pixels[index]; float b = brightness(c); if (b == 255) { field[i][j] = new PVector(2, 1); } else { float theta = map(b, 0, 255, 0, TWO_PI); field[i][j] = new PVector(cos(theta), sin(theta)); } } } } // eventually you might need to look at a pixel and its neighbors //float theta = map(noise(xoff,yoff),0,1,0,TWO_PI); // Polar to cartesian coordinate transformation to get x and y components of the vector // Draw every vector void display() { for (int i = 0; i < cols; i++) { for (int j = 0; j < rows; j++) { drawVector(field[i][j], i*resolution, j*resolution, resolution-2); } } } // // // Renders a vector object 'v' as an arrow and a location 'x,y' void drawVector(PVector v, float x, float y, float scayl) { pushMatrix(); float arrowsize = 4; // // Translate to location to render vector translate(x, y); stroke(0, 100); // // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate rotate(v.heading2D()); // // Calculate length of vector & scale it to be bigger or smaller if necessary float len = v.mag()*scayl; // // Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction) line(0, 0, len, 0); line(len, 0, len-arrowsize, +arrowsize/2); line(len, 0, len-arrowsize, -arrowsize/2); popMatrix(); } PVector lookup(PVector lookup) { int column = int(constrain(lookup.x/resolution, 0, cols-1)); int row = int(constrain(lookup.y/resolution, 0, rows-1)); return field[column][row].get(); } }