• fullscreen
  • fish.pde
  • fish_pond6v3.pde
  • food.pde
  • water.pde
  • //Nicholas Tang
    //3/25/11
    class fish {
    
      int len = 98, sp1, cp = 7, r = int(len/(cp-1));
      float[][] tailPath, cpoints;
      PVector pos, target, npos, vel;
      float dx = 0.4/3, th, vth, fisht, randt, ath, halfth, nth1, vth0 = 4*dx/60, acc, nsp, twist, newth, phi0, twist0, sz;
      color fcolor;
      PGraphics fishskin;
      boolean chasingfood;
    
      fish(float pos1, float pos2, float th1, int fcolor1, PGraphics fishskin1) {
        sp1 = sp10;
        //sz = 3 + 0.3*sqrt(2*log(1/(1-random(1))));
        sz = 3.35 + 0.225*sqrt(-2*log(random(1)))*sinLUT(TWO_PI*random(1));
        phi0 = random(TWO_PI);
        twist0 = 0;
        tailPath = new float[3][len];
        cpoints = new float[3][cp];
        pos = new PVector(pos1, pos2);
        npos = new PVector(pos1/sp1, pos2/sp1);
        vel = new PVector();
        th = th1;
        halfth = 0;
        nth1 = th;
        for (int i = 0; i < len; i++) {
          tailPath[0][i] = i*dx*sinLUT(th)+pos1/sp1;
          tailPath[1][i] = i*dx*cosLUT(th)+pos2/sp1;
          tailPath[2][i] = th;
        }
        for (int i = 0; i < cp; i++) {
          cpoints[0][i] = i*dx*sinLUT(th)+pos1/sp1;
          cpoints[1][i] = i*dx*cosLUT(th)+pos2/sp1;
          cpoints[2][i] = th;
        }
        fcolor = fcolor1;
        fishskin = fishskin1;
        fisht = 0;
        randt = round(random(50));
        boolean chasingfood = false;
        target = new PVector();
        vth = vth0;
        ath = dx/45;
        acc = 2;
        nsp = sp1;
      }
    
      void display() {
        int len2 = -31;
        int lenfin = 40;
        float[] y2 = new float[len];
        float[] thickness = new float[len];
        float[] tailR = new float[len];
        float[] tailL = new float[len];
        float[][] pHeadR = new float[2][abs(len2)];
        float[][] pHeadL = new float[2][abs(len2)];
        float[][] pFinR = new float[2][lenfin];
        float[][] pFinL = new float[2][lenfin];
        float[][] pEyeR = new float[2][lenfin];
        float[][] pEyeL = new float[2][lenfin];
        float[][] pTailR = new float[2][len];
        float[][] pTailL = new float[2][len];
        float squareScale = (60/8)*sz;
        float w = 0.22*squareScale;
        float s = 1;
        newth = atan2((sz/s)*abs(len2)*dx*cosLUT(-th)+sz*twist*sinLUT(th),(sz/s)*abs(len2)*dx*sinLUT(-th)+sz*twist*cosLUT(th))+3*HALF_PI;
        for (int i = 0; i < len-10; i++) {
          y2[i] = (squareScale*exp(0.1/1.25*(i*dx-30))-squareScale*exp(0.1/1.25*(-30)));
          thickness[i] = w*(cosLUT(PI/(len*dx)*i*dx)+1)*0.5*int(i<len);
          tailR[i] = y2[i] + thickness[i];
          tailL[i] = y2[i] - thickness[i];
          pTailR[0][i] = tailR[i]*cosLUT(tailPath[2][i])+sz*tailPath[0][i]-sz*npos.x;
          pTailR[1][i] = tailR[i]*sinLUT(tailPath[2][i])+sz*tailPath[1][i]-sz*npos.y;
          pTailL[0][i] = tailL[i]*cosLUT(tailPath[2][i])+sz*tailPath[0][i]-sz*npos.x;
          pTailL[1][i] = tailL[i]*sinLUT(tailPath[2][i])+sz*tailPath[1][i]-sz*npos.y;
        }
        for (int i = 0; i < abs(len2); i++) {
          pHeadR[0][i] = -sz*twist*cosLUT(th)+(sqrt(1-pow((((i+1)+len2)*dx),2)/pow(4,2))*w)*cosLUT(newth)+sz*(((i+1)+len2)*dx)*cosLUT(newth-HALF_PI);
          pHeadR[1][i] = -sz*twist*sinLUT(th)+(sqrt(1-pow((((i+1)+len2)*dx),2)/pow(4,2))*w)*sinLUT(newth)+sz*(((i+1)+len2)*dx)*sinLUT(newth-HALF_PI);
          pHeadL[0][i] = -sz*twist*cosLUT(th)-(sqrt(1-pow((((i+1)+len2)*dx),2)/pow(4,2))*w)*cosLUT(newth)+sz*(((i+1)+len2)*dx)*cosLUT(newth-HALF_PI);
          pHeadL[1][i] = -sz*twist*sinLUT(th)-(sqrt(1-pow((((i+1)+len2)*dx),2)/pow(4,2))*w)*sinLUT(newth)+sz*(((i+1)+len2)*dx)*sinLUT(newth-HALF_PI);
        }
        float scfin = (PI/3)/lenfin;
        float sceye = (TWO_PI)/lenfin;
        float ecc = 1.25;
        float sc = 0.15*sz;
        float eyex = 2.5*sz;
        float eyey = (7*w)/16;
        for (int i = 0; i < lenfin; i++) {
          pFinR[0][i] = -sz*twist*cosLUT(th)+2*sinLUT(-newth)+w*cosLUT(newth)+sz*2*sinLUT(3*i*scfin)*sinLUT(i*scfin+PI/6+HALF_PI+PI/24-newth);
          pFinR[1][i] = -sz*twist*sinLUT(th)+2*cosLUT(-newth)+w*sinLUT(newth)+sz*2*sinLUT(3*i*scfin)*cosLUT(i*scfin+PI/6+HALF_PI+PI/24-newth);
          pFinL[0][i] = -sz*twist*cosLUT(th)+2*sinLUT(-newth)-w*cosLUT(newth)+sz*2*sinLUT(3*i*scfin)*sinLUT(i*scfin+PI/6+PI/3+HALF_PI-PI/24-newth); 
          pFinL[1][i] = -sz*twist*sinLUT(th)+2*cosLUT(-newth)-w*sinLUT(newth)+sz*2*sinLUT(3*i*scfin)*cosLUT(i*scfin+PI/6+PI/3+HALF_PI-PI/24-newth);
          pEyeR[0][i] = -sz*twist*cosLUT(th)+eyey*cosLUT(newth)+eyex*sinLUT(-newth)+sc*(ecc*sinLUT(i*sceye)*cosLUT(newth+HALF_PI)-cosLUT(i*sceye)*sinLUT(newth+HALF_PI)); 
          pEyeR[1][i] = -sz*twist*sinLUT(th)+eyey*sinLUT(newth)+eyex*cosLUT(-newth)+sc*(cosLUT(newth+HALF_PI)*cosLUT(i*sceye)+ecc*sinLUT(i*sceye)*sinLUT(newth+HALF_PI));
          pEyeL[0][i] = -sz*twist*cosLUT(th)-eyey*cosLUT(newth)+eyex*sinLUT(-newth)+sc*(ecc*sinLUT(i*sceye)*cosLUT(newth+HALF_PI)-cosLUT(i*sceye)*sinLUT(newth+HALF_PI)); 
          pEyeL[1][i] = -sz*twist*sinLUT(th)-eyey*sinLUT(newth)+eyex*cosLUT(-newth)+sc*(cosLUT(newth+HALF_PI)*cosLUT(i*sceye)+ecc*sinLUT(i*sceye)*sinLUT(newth+HALF_PI));
        }
        pg.pushMatrix();
        pg.translate(width/2+pos.x,height/2+pos.y);
        pg.fill(palette2[fcolor]);
        pg.stroke((palette2[fcolor] & 0xffffff) | (89 << 24));
        drawShape(lenfin,pFinR);
        drawShape(lenfin,pFinL);
        pg.fill((palette2[fcolor] & 0xffffff) | (142 << 24));
        pg.noStroke();
        pg.beginShape(TRIANGLE_STRIP);
        pg.texture(fishskin);
        for (int i = 0; i < abs(len2); i++) {
          pg.vertex(pHeadL[0][i]/.4,pHeadL[1][i]/.4,fishskin.width-i,fishskin.height);
          pg.vertex(pHeadR[0][i]/.4,pHeadR[1][i]/.4,fishskin.width-i,0);
        }
        for (int i = 0; i <= len-15-10; i++) {
          pg.vertex(pTailL[0][i]/.4,pTailL[1][i]/.4,fishskin.width-(i-1+abs(len2)),fishskin.height);
          pg.vertex(pTailR[0][i]/.4,pTailR[1][i]/.4,fishskin.width-(i-1+abs(len2)),0);
        }
        pg.endShape();
        pg.beginShape();
        for (int i = len-15-10; i < len-10; i++) {
          pg.vertex(pTailR[0][i]/.4,pTailR[1][i]/.4);
        }
        for (int i = len-1-10; i > len-1-15-10; i--) {
          pg.vertex(pTailL[0][i]/.4,pTailL[1][i]/.4);
        }
        pg.endShape();
        pg.fill(0);
        pg.stroke(0);
        drawShape(lenfin,pEyeR);
        drawShape(lenfin,pEyeL);
        pg.popMatrix();
    
        if (chasingfood) {
          if (nsp > sp1) {
            twist0+=0.07;
          } 
          else {
            twist0-=0.05;
          }
          twist0 = constrain(twist0,0,0.3);
          twist = twist0*sinLUT(t*(QUARTER_PI)+phi0);
        } 
        else {
          if ((abs(nsp-sp1)<10) && (fisht > 5+randt - 6)) {
            twist0+=0.05;
          } 
          else {
            twist0-=0.005;
          }
          twist0 = constrain(twist0,0,0.4);
          twist = twist0*sinLUT(t*(PI/10)+phi0);
        }
        //twist = twist0*sinLUT(t*(PI/(4+(abs(nsp-75)/10)))+phi0);
      }
    
      void update() {
        updateangle(nth1);
        updatespeed();
        npos.x += dx*cosLUT(th+HALF_PI);
        npos.y += dx*sinLUT(th+HALF_PI);
        float[][] newcpoints = new float[3][cp];
        newcpoints[0][0] = npos.x-twist*cosLUT(th);
        newcpoints[1][0] = npos.y-twist*sinLUT(th);
        newcpoints[2][0] = newth;
        for (int i = 0; i < cp-1; i++) {
          newcpoints[0][i+1] = cpoints[0][i] + dx*r*cosLUT((cpoints[2][i]+cpoints[2][i+1])/2-HALF_PI);
          newcpoints[1][i+1] = cpoints[1][i] + dx*r*sinLUT((cpoints[2][i]+cpoints[2][i+1])/2-HALF_PI);
          newcpoints[2][i+1] = cpoints[2][i];
        }
        cpoints = newcpoints;
        for (int i = 0; i < cp-1; i++) {
          tailPath[0][i*r] = cpoints[0][i];
          tailPath[1][i*r] = cpoints[1][i];
          tailPath[2][i*r] = cpoints[2][i];
          for (int j = 1; j < r; j++) {
            tailPath[0][i*r+j] = curvePoint(cpoints[0][max(i-1,0)],cpoints[0][i],cpoints[0][i+1],cpoints[0][min(i+2,cp-1)],j*1./r);
            tailPath[1][i*r+j] = curvePoint(cpoints[1][max(i-1,0)],cpoints[1][i],cpoints[1][i+1],cpoints[1][min(i+2,cp-1)],j*1./r);
            tailPath[2][i*r+j] = atan2(curveTangent(cpoints[1][max(i-1,0)],cpoints[1][i],cpoints[1][i+1],cpoints[1][min(i+2,cp-1)],j*1./r),
            curveTangent(cpoints[0][max(i-1,0)],cpoints[0][i],cpoints[0][i+1],cpoints[0][min(i+2,cp-1)],j*1./r))+HALF_PI;
          }
        }
      }
    
      void updateangle(float nth) {
        float diffth = nth-th;
        if (sign(nth1-th) != sign(diffth)) {
          vth = vth0;
        }
        nth1 = nth;
        halfth = -vth*((vth-vth0)/ath)+(ath/2)*pow((vth-vth0)/ath,2);
        if (abs(diffth) > abs(vth)) {
          if (abs(diffth) > abs(halfth)) {
            vth += ath;
          } 
          else {
            vth -= ath;
          }
          vth = max(vth, vth0);
          th += sign(diffth)*vth;
        } 
        else {
          th += diffth;
          vth = vth0;
        }
      }
      void updatespeed() {
        float diffsp = nsp - sp1;
        if (abs(diffsp) > acc) {
          if (sign(diffsp) == 1) {
    //        ripple(int(pos.x+width/2+cosLUT(th+HALF_PI)*31),int(pos.y+height/2+sinLUT(th+HALF_PI)*31),
    //        int(pos.x+width/2+cosLUT(th+HALF_PI)*31),int(pos.y+height/2+sinLUT(th+HALF_PI)*31));
            sp1 += acc*2;
          } 
          else {
            sp1 -= acc;
          }
        } 
        else {
          sp1 += diffsp;
        }
        vel.set(sp1*dx*cosLUT(th+HALF_PI), sp1*dx*sinLUT(th+HALF_PI),0);
        pos.add(vel);
      }
    }
    
    void drawShape(int len, float[][] shapes) {
      pg.beginShape();
      for (int i = 0; i < len; i++) {
        pg.vertex(shapes[0][i]/.4,shapes[1][i]/.4);
      }
      pg.endShape();
    }
    
    
    //Nicholas Tang
    //3/25/11
    int t, numfish, cnum, cnum2, sp10 = 35, period, gwidth, gheight;
    ArrayList fishes, foods;
    PImage scaleTemplate;
    PImage caustics[];
    PGraphics pg, fishskin;
    PGraphics[] causticss;
    PVector v1,v2,v3,v4,v5;
    color[] palette = new color[5], palette2 = new color[5];
    float increment = 0.075, zrand, invprec;
    boolean leavechasing;
    float[] sinTable, cosTable;
    float[][] z, dz;
    
    void setup() {
      frameRate(17);
      v1 = new PVector();
      v2 = new PVector(); 
      v3 = new PVector();
      v4 = new PVector(); 
      gwidth = (width/gridSize)+1;
      gheight = height/gridSize;
      z = new float[gwidth][gheight];
      dz = new float[gwidth][gheight];
      invprec = 1000;
      period = int(360*invprec);
      sinTable = new float[period*2];
      cosTable = new float[period*2];
      for (int i = 0; i < period*2; i ++) {
        sinTable[i] = sin(radians(i/invprec));
        cosTable[i] = cos(radians(i/invprec));
      }
      scaleTemplate = loadImage("fishscale.png");
      colorMode(HSB,360);
      palette[0] = color(0,360,0.05*360); // black
      palette[1] = color(250, .03*360, 360); //white
      palette[2] = color(352, 360, 0.75*360); //red
      palette[3] = color(48, .97*360, 0.98*360); //yellow
      palette[4] = color(29,0.96*360,0.94*360); //orange
      for (int i = 0; i < 5; i++) {
        palette2[i] = color(hue(palette[i]), saturation(palette[i])-50, brightness(palette[i]), 300);
      }
      leavechasing = false;
      size(900,500,P3D);
      pg = createGraphics(900, 500, P3D);
      numfish = 25;
      t = 0;
      foods = new ArrayList();
      fishes = new ArrayList();
      for (int i = 1; i < numfish+1; i++) {
        fishskin = skin();
        fishes.add(new fish((-width/2)-random(width*1.5),-(height/2)+(floor(random(numfish))*(height/numfish)),(3*PI)/2,cnum2,fishskin));
      }
      caustics = new PImage[30];
      causticss = new PGraphics[30];
      for (int i = 0; i < 30; i ++) {
        caustics[i] = loadImage("caustics_" + nf(i+1,3) + ".bmp");
        caustics[i].resize(450,500);
        causticss[i] = seam(caustics[i],i);
      }
    }
    
    void draw() {
      pg.beginDraw();
      pg.background(causticss[t%30]);
      //pg.background(215,360,175);
      t ++;
      //println(frameRate);
      for (int i = fishes.size()-1; i >= 0; i--) { 
        fish fish1 = (fish) fishes.get(i);
        float fisht = fish1.fisht;
        float randt = fish1.randt;
        fisht ++;
        fish1.display();
        if (fisht%2 == 0) {
          detectfood(fish1,i);
        }
        //    if (t == 1){
        //      fish1.updateangle(fish1.th+sign(random(-0.001,0.001))*random(PI/4));
        //    }
        if ((fisht%(5+randt) == 0) && (fish1.chasingfood == false)) {
          if (leavechasing) {
            fish1.updateangle(3*PI/2+sign(sinLUT(t))*random(PI/12));
            leavechasing = false;
          } 
          else {
            fish1.updateangle(fish1.th+sign(sinLUT(t))*random(PI/12));
          }
          fisht = 0;
          randt = round(random(70));
        }
        fish1.fisht = fisht;
        fish1.randt = randt;
        fish1.update();
        if ((fish1.pos.x > ((width/2)+100)) || (fish1.pos.y > ((height/2)+100)) || (fish1.pos.y < -((height/2)+100))) {
          fishes.remove(i);
          fishskin = skin();
          fishes.add(new fish(-(width/2)-random((3*width)/2)-50,-(height/2)+(floor(random(numfish))*(height/numfish)),(3*PI)/2,cnum2,fishskin));
        }
      }
      pg.endDraw();
      if (mousePressed) {
        foods.add(new food(mouseX, mouseY,random(65)));
        ripple(mouseX, mouseY, pmouseX, pmouseY);
      }
      water(pg);
    }
    
    float sign(float a) {
      if (a > 0) {
        return 1;
      } 
      else if (a == 0) {
        return 0;
      } 
      else {
        return -1;
      }
    }
    
    PGraphics skin() {
      color c1, c2, c1n, c2n;
      cnum = floor(random(4.99));
      cnum2 = floor(random(3.99)+1);
      if ((cnum2 > 1) && (cnum > 1)) {
        if (boolean(round(random(1)))) {
          cnum2 = cnum;
        } 
        else {
          if (cnum == 2){
            cnum2 = 1;
          } else{
            cnum = 1;
          }
        }
      }
      if ((cnum == 1) && (cnum2 > 2)) {
        cnum2 = 2;
      }
      if ((cnum2 == 1) && (cnum > 1)) {
        //cnum = 1+round(random(1));
        cnum = 2;
      }
      c1n = palette[cnum];
      c2n = palette[cnum2];
      PGraphics scales = createGraphics(98+31-15, int(0.2*((60/8)*3)/.4*2)+1,P2D);
      noiseDetail(2,1.5);
      scales.loadPixels();
      float yoff = 0.0;
      for (int y = 0; y < scales.height; y++) {
        yoff += increment;
        float xoff = 0.0;
        float b2lim = 0.6;
        if (cnum != 0) {
          c1 = color(hue(c1n),saturation(c1n),sqrt(pow(scales.height/2,2)-pow((y-scales.height/2),2))*((360*2)/scales.height));
        } 
        else {
          c1 = c1n;
        }
        c2 = color(hue(c2n),saturation(c2n),sqrt(pow(scales.height/2,2)-pow((y-scales.height/2),2))*((360*2)/scales.height));
        for (int x = 0; x < scales.width; x++) {
          xoff += increment;
          int bright = int(noise(xoff,yoff,zrand) > 0.6);
          int bright2 = int(noise(xoff,yoff,zrand) > b2lim);
          if (x<98-15-8) {
            scales.pixels[x+y*scales.width] = c1*int(bright==1) + c2*int(bright==0);
            //scales.pixels[x+y*scales.width] = c1;
          } 
          else {
            scales.pixels[x+y*scales.width] = c1*int(bright2==1) + c2*int(bright2==0);
            //scales.pixels[x+y*scales.width] = c2;
            b2lim += 0.014;
          }
        }
      }
      zrand +=PI;
      scales.mask(scaleTemplate);
      return scales;
    }
    
    void detectfood(fish fish1, int i) {
      PVector pos = new PVector(fish1.pos.x+width/2+cosLUT(fish1.th+PI/2)*31,fish1.pos.y+height/2+sinLUT(fish1.th+PI/2)*31);
      int p = 0;
      boolean chasingfood = false;
      float [][] targets = new float[2][128];
      for (int j = foods.size()-1; j >= 0; j--) { 
        food food1 = (food) foods.get(j);
        if (i == fishes.size()-1) {
          food1.die = 20;
        }
        if (PVector.dist(pos,food1.pos) < food1.die) {
          food1.die = PVector.dist(pos,food1.pos);
        }
        if (food1.die < 10) {
          food1.death = true;
        }
        if (food1.death && ((food1.die > 10) || (food1.die < 2))) {
          //ripple(int(food1.pos.x),int(food1.pos.y),int(food1.pos.x),int(food1.pos.y));
          foods.remove(j);
          fish1.nsp = sp10;
          fish1.fisht = fish1.randt;
          leavechasing = true;
        } 
        else if ((PVector.dist(pos,food1.pos) < 350) && (pos.x < food1.pos.x) && !((abs(food1.pos.y-pos.y)/abs(food1.pos.x-pos.x) > 3) && (abs(food1.pos.x-pos.x) < 40))) {
          if (p < 128) {
            targets[0][p] =  food1.pos.x;
            targets[1][p] =  food1.pos.y;
            p += 1;
          }
          if ((fish1.target.x == food1.pos.x) && (fish1.target.y == food1.pos.y)) {
            chasingfood = true;
            fish1.nsp = 75*fish1.sz/3;
            //        float posth = -fish1.sp1*fish1.dx*((fish1.sp1-sp10)/fish1.acc)+((fish1.acc*fish1.dx)/2)*pow((fish1.sp1-sp10)/fish1.acc,2);
            //        if (PVector.dist(pos,food1.pos) < -posth){
            //          fish1.nsp = sp10;
            //        }
            float dth = PVector.angleBetween(PVector.sub(food1.pos,pos), new PVector(cosLUT(fish1.th), sinLUT(fish1.th)));
            fish1.updateangle(fish1.th+dth-PI/2);
          }
        }
      }
      if ((fish1.chasingfood == true) && (chasingfood == false)) {
        fish1.nsp = sp10;
        fish1.fisht = fish1.randt;
        leavechasing = true;
      }
      fish1.chasingfood = chasingfood;
      //  fish1.target.x = targets[0][floor(random(p))];
      //  fish1.target.x = targets[1][floor(random(p))];
      fish1.target.x = targets[0][0];
      fish1.target.y = targets[1][0];
      for (int k = 1; k < p; k++) {
        if (fish1.target.x > targets[0][k]) {
          fish1.target.x = targets[0][k];
          fish1.target.y = targets[1][k];
        }
      }
    }
    
    float sinLUT(float rad) {
      return sinTable[(int(degrees(rad)*invprec) % period) + period];
    }
    
    float cosLUT(float rad) {
      return cosTable[(int(degrees(rad)*invprec) % period) + period];
    }
    
    PGraphics seam(PImage inp, int i) {
      PGraphics ret = createGraphics(width, height, P2D);
      ret.beginDraw();
      //-inp.width+int(i*(inp.width*1./60))
      for(int j=0; j<=width; j+=inp.width) {
        ret.copy(inp,0,0,inp.width,inp.height,j,0,inp.width,inp.height);
      }
      ret.endDraw();
      return ret;
    }
    
    
    
    //Nicholas Tang
    //3/25/11
    class food {
      PVector pos;
      float foodcolor1;
      float die;
      boolean death;
    
      food(float pos1, float pos2, float foodcolor) {
        pos = new PVector(pos1, pos2);
        foodcolor1 = foodcolor;
        die = 20;
        death = false;
      }
    }
    
    
    //Nicholas Tang
    //3/25/11
    int gridSize=20;
    float xoff,zoff,ns=0.25,zs=130,power = 2.5, avgz, impulse = -0.5;
    PImage tex;
    
    void water(PGraphics tex) {
      //  if ((mouseX == 0) && (mouseY == 0)){
      //    camera(width/2, height/2-60+270/1.85, 520-270/50-(250-width/2+300)/3.5, width/2, height/2, 0.0, -0.0, 1.0, 0.0);
      //  } else{
      //  camera(width/2, height/2-60+mouseY/1.85, 520-mouseY/50-(mouseX-width/2+400)/1.67, // eyeX, eyeY, eyeZ
      //         width/2, height/2, 0.0, // centerX, centerY, centerZ
      //         -0.0, 1.0, 0.0); // upX, upY, upZ
      //  }
      noStroke();
      background(tex);
      updatez();
    
      colorMode(RGB, 255);
      if (t == 1) {
        specular(255, 255, 255);
        shininess(50);
      }
      pointLight(255, 255, 255, width, height/2, 100);
      pointLight(255, 255, 255, width/2, height, 100);
      ambientLight(30, 30, 30);
      lightSpecular(95, 95, 95);
      directionalLight(115, 115, 115, 1, 1, -1);
      directionalLight(115, 115, 115, -1, -1, -1);
      spotLight(45, 45, 45, -100, 230, 800, 1, 0, -1, PI/3, 5);
      noiseDetail(8,200*(0.6/height));
      float nx,ny=0,z1,z2;
      colorMode(HSB, 360);
      
      fill(255,0,0,75);
      for(int y=0; y<gheight; y++) {
        nx=xoff;
        beginShape(TRIANGLE_STRIP);
        for(int x=0; x<gwidth; x++) {
          z1=pow(noise(nx,ny,zoff),power);
          z2=pow(noise(nx,ny+ns,zoff),power);
          surfnorm(x,y,nx,ny);
          normal(v5.x,v5.y,v5.z);
          vertex(x*gridSize,y*gridSize);
          surfnorm(x,y+1,nx,ny+ns);
          normal(v5.x,v5.y,v5.z);
          vertex(x*gridSize,(y+1)*gridSize);
          nx+=ns;
        }
        endShape();
        ny+=ns;
      }
    
      for (int i = foods.size()-1; i >= 0; i--) { 
        food food1 = (food) foods.get(i);
        pushMatrix();
        translate(0,0,z[int(constrain(food1.pos.x,0,gwidth-2)/gridSize)][int(constrain(food1.pos.y,0,gheight-2)/gridSize)]*50+pow(noise(ns*(food1.pos.x/gridSize)+xoff,ns*(food1.pos.y/gridSize),zoff),power)*zs);
        fill(food1.foodcolor1,.9*360,.55*360);
        ellipseMode(CENTER);
        if (food1.death) {
          ellipse(food1.pos.x,food1.pos.y,4,4);
          //      sphereDetail(2);
          //      sphere(2);
        } 
        else {
          ellipse(food1.pos.x,food1.pos.y,6,6);
          //      sphereDetail(3);
          //      sphere(3.5);
        }
        popMatrix();
      }
    
      zoff+=0.045;
      xoff-=0.06;
    }
    
    void updatez() {
      for(int x=1; x<gwidth-1; x++) {
        for(int y=1; y<gheight-1; y++) {
          avgz = (z[x-1][y] + z[x+1][y] + z[x][y-1] + z[x][y+1])*0.25;
          dz[x][y] += (avgz - z[x][y])*2;
          dz[x][y] *= 0.9;
        }
      }
      for(int x=1; x<gwidth-1; x++) {
        for(int y=1; y<gheight-1; y++) {
          z[x][y] += dz[x][y];
        }
      }
    }
    
    void ripple(int x0, int y0, int x1, int y1) {
      x0 = constrain(x0/gridSize, 0, gwidth-2);
      y0 = constrain(y0/gridSize, 0, gheight-2);
      x1 = constrain(x1/gridSize, 0, gwidth-2);
      y1 = constrain(y1/gridSize, 0, gheight-2);
      int xi = 0, yi = 0;
      for (int i=0; i<=int(dist(x0,y0,x1,y1)); i++) {
        xi = int(x0+(i/max(1,float(int(dist(x0,y0,x1,y1)))))*(x1-x0));
        yi = int(y0+(i/max(1,float(int(dist(x0,y0,x1,y1)))))*(y1-y0));
        dz[xi][yi] += impulse;
        dz[xi+1][yi] += impulse;
        dz[xi][yi+1] += impulse;
        dz[xi+1][yi+1] += impulse;
      }
    }
    
    void surfnorm(int x, int y, float nx, float ny) {
      float z0 = z[x%gwidth][y%gheight]*(50/zs)+pow(noise(nx,ny,zoff),power);
      float z1 = z[x%gwidth][(y+1)%gheight]*(50/zs)+pow(noise(nx,ny+ns,zoff),power);
      float z2 = z[(x+1)%gwidth][y%gheight]*(50/zs)+pow(noise(nx+ns,ny,zoff),power);
      float z3 = z[x%gwidth][abs(y-1)%gheight]*(50/zs)+pow(noise(nx,ny-ns,zoff),power);
      float z4 = z[abs(x-1)%gwidth][y%gheight]*(50/zs)+pow(noise(nx-ns,ny,zoff),power);
      v1.set(0, gridSize, (z1-z0)*zs);
      v2.set(gridSize, 0, (z2-z0)*zs);
      v3.set(0, -gridSize, (z3-z0)*zs);
      v4.set(-gridSize, 0, (z4-z0)*zs);
      v5 = PVector.add(PVector.add(v1.cross(v2),v2.cross(v3)),PVector.add(v3.cross(v4),v4.cross(v1)));
      v5.normalize();
    }
    
    

    code

    tweaks (0)

    license

    advertisement

    Nicholas Tang

    Koi Pond v5

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

    Click to make ripples.

    Added caustic effects. Koi sizes are now gaussian distributed.

    edit (4/07): Drawing screen buffer using background() instead of image() significantly improved fps performance.

    SiV
    26 Mar 2011
    really nice!!! bravo!!
    AndyKid
    4 Oct 2012
    Hello, I really love this, can you please help me how to make the fish go from the right to left. I don't know how. Thank you.
    You need to login/register to comment.