• fullscreen
  • Water.pde
  • int heightMap[][][]; // water surface (2 pages).
    int turbulenceMap[][]; // turbulence map
    int line[]; // line optimizer;
    int space;
    int radius, heightMax, density;
    int page = 0;
    PImage water;
    
    void setup() {
      size(512, 512);
      initWater();
      initMap();
    }
    
    void draw() {
      waterFilter();
      updateWater();
      page ^= 1; // page switching.
    }
    
    void initWater() {
      float zoff = 0;
      water = new PImage(width,height);
      water.loadPixels();
      for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
          zoff += 0.0001f;
          float bright = ((noise(x*0.01f, y*0.01f, zoff)) * 255);
          water.pixels[x + y * width] = 0xFF000000 | ((int) bright);
        }
      }
      water.updatePixels();
      water.filter(BLUR, 4.5f);
    }
    
    void initMap() {
      // the height map is made of two "pages". 
      // one to calculate the current state, and another to keep the previous state.
      heightMap = new int[2][width][height];
      line = new int[height];
      for (int l = 0; l < height; l++) {
        line[l] = l * width;
      }
      density = 5;
      radius = 20;
      space = width * height - 1;
    
      // the turbulence map, is an array to make a smooth turbulence over the height map.
      turbulenceMap = new int[radius * 2][radius * 2]; // turbulence map.
      int r = radius * radius;
      int squarex, squarey;
      double dist;
    
      for (int x = -radius; x < radius; x++) {
        squarex = x * x;
        for (int y = -radius; y < radius; y++) {
          squarey = y * y;
          dist = Math.sqrt(squarex + squarey);
          if ((squarex) + (squarey) < r) {
            turbulenceMap[radius + x][radius + y] += (int) (900 * ((float) radius - dist));
          }
        }
      }
    }
    
    // to make a turbulence, just add the turbulence map, over the height map.
    void makeTurbulence(int cx, int cy) {
      int r = radius * radius;
      int left = cx < radius ? -cx + 1 : -radius;
      int right = cx > (width - 1) - radius ? (width - 1) - cx : radius;
      int top = cy < radius ? -cy + 1 : -radius;
      int bottom = cy > (height - 1) - radius ? (height - 1) - cy : radius;
    
      for (int x = left; x < right; x++) {
        int xsqr = x * x;
        for (int y = top; y < bottom; y++) {
          if ((xsqr) + (y * y) < r)
            heightMap[page ^ 1][cx + x][cy + y] += turbulenceMap[radius	+ x][radius + y];
        }
      }
    }
    
    private void waterFilter() {
      for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
          int n = y - 1 < 0 ? 0 : y - 1;
          int s = y + 1 > (height) - 1 ? (height) - 1 : y + 1;
          int e = x + 1 > (width) - 1 ? (width) - 1 : x + 1;
          int w = x - 1 < 0 ? 0 : x - 1;
    
          // water filter. I used to thought that this effect
          // had something to do with physics... :)
    
          // it a kind of image filter, but instead of applying to an image,
          // we apply it to the height map, that encodes the height of the waves.
          int value = ((heightMap[page][w][n] + heightMap[page][x][n]
            + heightMap[page][e][n] + heightMap[page][w][y]
            + heightMap[page][e][y] + heightMap[page][w][s]
            + heightMap[page][x][s] + heightMap[page][e][s]) >> 2)
            - heightMap[page ^ 1][x][y];
    
          heightMap[page ^ 1][x][y] = value - (value >> density);
        }
      }
    }
    
    private void updateWater() {
      loadPixels();
      arraycopy(water.pixels, pixels); // not really needed...
      for (int y = 0; y < height - 1; y++) {
        for (int x = 0; x < width - 1; x++) {
          // using the heightmap to distort underlying image
          int deltax = heightMap[page][x][y] - heightMap[page][(x) + 1][y];
          int deltay = heightMap[page][x][y] - heightMap[page][x][(y) + 1];
    
          int offsetx = (deltax >> 3) + x;
          int offsety = (deltay >> 3) + y;
    
          offsetx = offsetx > width ? width - 1 : offsetx < 0 ? 0	: offsetx;
          offsety = offsety > height ? height - 1 : offsety < 0 ? 0 : offsety;
    
          int offset = (offsety * width) + offsetx;
          offset = offset < 0 ? 0 : offset > space ? space : offset;
          // Getting the water pixel with distortion and...
          // apply some fake lightning, in true color.
          int pixel = water.pixels[offset];
          int red = (pixel >> 16) & 0xff;
          int green = (pixel >> 8) & 0xff;
          int blue = (pixel) & 0xff;
          int light = (deltax + deltay) >> 6;
          red += light;
          green += light;
          blue += light;
          red = red > 255 ? 255 : red < 0 ? 0 : red;
          green = green > 255 ? 255 : green < 0 ? 0 : green;
          blue = blue > 255 ? 255 : blue < 0 ? 0 : blue;
          // updating our image source.
          pixels[line[y] + x] = 0xff000000 | (red << 16) | (green << 8) | blue;
        }
      }
      updatePixels();
    }
    
    void mouseDragged(){
      makeTurbulence(mouseX,mouseY);
    }
    
    void mousePressed() {
      makeTurbulence(mouseX,mouseY);
    }
    

    code

    tweaks (0)

    about this sketch

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

    license

    advertisement

    Report Sketch

    Report for inappropriate content

    Please provide details if possible:

    Your have successfully reported the sketch. Thank you very much for helping to keep OpenProcessing clean and tidy :)

    Make a Copyright Infringement claim

    Rui Gil
    Daniel Piker
    21 Nov 2008
    This is nice - simple and effective
    Rui Gil
    21 Nov 2008
    Thanks! Althought I think it's obvious, I should say I didn't invent this... This is an old skool demo trick from the 90's. My only contribution was the turbulence map, to give it a nice smooth look.
    Xiaohan Zhang
    3 May 2009
    beautifully realistic. i've often thought about making some sort of water visualization, with this exact type of effect in mind. well done!
    alex
    19 Jan 2016
    hey is there a way to contact you via email?
    You need to login/register to comment.