Creating variation in grid with random(); & image

Hi @asymmetric,

It’s unclear for me what this really means. By morphing you mean having an animation or just have a random displacement effect on the grid?

Also which interaction do you want with the image? Is it the diagonal orientation that will depend on the pixel color? (either 0 or 1)

Here is an implementation where I use line() because I find it easier:

int borderGap = 60;
int resolution = 10;
int maxHeight = 70;

class Grid {
  PVector[][] points;

  Grid(int resolution, int borderGap) {
    points = new PVector[resolution][resolution];

    float spaceBetweenPoints = (float) (width - (2 * borderGap)) / (resolution - 1);

    // Construct points
    for (int i = 0; i < resolution; i++) {
      float x = borderGap + i * spaceBetweenPoints;
      for (int j = 0; j < resolution; j++) {
        float y = borderGap + j * spaceBetweenPoints;
        float pointHeight = random(maxHeight);
        points[i][j] = new PVector(x, y, pointHeight);
      }
    }
  }

  void diagonal(int i, int j) {
    // Choose a random direction
    boolean randDiag = random(1) < 0.5;

    // Alternate the i index
    lineBetween(
      points[i + (randDiag ? 1 : 0)][j], 
      points[i + (randDiag ? 0 : 1)][j + 1]
      );
  }

  void displayHorizontalLines() {
    stroke(255);
    strokeWeight(1);

    for (int j = 0; j < resolution; j++) {
      for (int i = 0; i < resolution - 1; i++) {
        lineBetween(points[i][j], points[i + 1][j]);

        if (j < resolution - 1) {
          diagonal(i, j);
        }
      }
    }
  }

  void displayVerticalLines() {
    stroke(255);
    strokeWeight(1);

    for (int i = 0; i < resolution; i++) {
      for (int j = 0; j < resolution - 1; j++) {
        lineBetween(points[i][j], points[i][j + 1]);
      }
    }
  }

  void displayPoints() {
    strokeWeight(8);
    stroke(200, 50, 200);

    for (int i = 0; i < resolution; i++) {
      for (int j = 0; j < resolution; j++) {
        PVector P = points[i][j];
        point(P.x, P.y, P.z);
      }
    }
  }

  void display() {
    displayHorizontalLines();
    displayVerticalLines();
    displayPoints();
  }
}

Grid grid;

void setup() {
  size(500, 500, P3D);

  grid = new Grid(resolution, borderGap);
}

void lineBetween(PVector A, PVector B) {
  line(A.x, A.y, A.z, B.x, B.y, B.z);
}

void draw() {
  background(0);
  
  grid.display();

  noLoop();
}

Currently this implementation does not store the diagonal data in the Grid which means that if you were to animate it, it would recompute the diagonal orientation every time and flicker. You might want to store it for each face. (a boolean value or 0 / 1)

Here is another implementation using beginShape(TRIANGLE_STRIP) and storing diagonal data. It was more tricky to figure out :innocent:

int borderGap = 60;
int resolution = 10;
int maxHeight = 70;

void vertexP(PVector P) {
  vertex(P.x, P.y, P.z);
}

/**
 * Give vertices in this order:
 *
 *  A -- B
 *  |    |
 *  D -- C
 */
void triangulatedFace(PVector A, PVector B, PVector C, PVector D, boolean flipDiagonal) {
  // B -> A -> C -> D
  if (flipDiagonal) {
    vertexP(B);
    vertexP(A);
    vertexP(C);
    vertexP(D);
  } else {
    // A -> D -> B -> C
    vertexP(A);
    vertexP(D);
    vertexP(B);
    vertexP(C);
  }
}

class Grid {
  PVector[][] points;
  boolean[][] diagonals;

  Grid(int resolution, int borderGap) {
    points = new PVector[resolution][resolution];
    diagonals = new boolean[resolution][resolution];

    float spaceBetweenPoints = (float) (width - (2 * borderGap)) / (resolution - 1);

    // Construct points
    for (int i = 0; i < resolution; i++) {
      float x = borderGap + i * spaceBetweenPoints;
      for (int j = 0; j < resolution; j++) {
        float y = borderGap + j * spaceBetweenPoints;
        float pointHeight = random(maxHeight);
        points[i][j] = new PVector(x, y, pointHeight);
        
        // Store diagonal info, with 1/2 flip
        diagonals[i][j] = random(1) < 0.5;
      }
    }
  }

  void displayPoints() {
    strokeWeight(8);
    stroke(200, 50, 200);

    for (int i = 0; i < resolution; i++) {
      for (int j = 0; j < resolution; j++) {
        PVector P = points[i][j];
        point(P.x, P.y, P.z);
      }
    }
  }
  
  void displayTriangleStrips() {
    stroke(255);
    strokeWeight(1);
    noFill();

    for (int j = 0; j < resolution - 1; j++) {
      for (int i = 0; i < resolution - 1; i++) {
        beginShape(TRIANGLE_STRIP);
        
        triangulatedFace(
          points[i][j], 
          points[i + 1][j], 
          points[i + 1][j + 1], 
          points[i][j + 1], 
          diagonals[i][j]
        );
        
        endShape();
      }
    }
  }

  void display() {
    displayTriangleStrips();
    displayPoints();
  }
}

Grid grid;

void setup() {
  size(500, 500, P3D);

  grid = new Grid(resolution, borderGap);
}

void draw() {
  background(0);

  grid.display();

  noLoop();
}

→ With a resolution of 200 for the grid, the frameRate was around 14 fps using line() and 12 using TRIANGLE_STRIP. Maybe my second implementation is not optimal thought…

Then you can influence your grid with an image…

Hope it helps! :wink: