# Creating variation in grid with random(); & image

**URL:** <https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135>\
**Category:** Coding Questions\
**Created:** [December 12, 2022, 6:26pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135 "2022-12-12T18:26:44Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 12, 2022, 6:26pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/1 "2022-12-12T18:26:44Z")

</div>

I’m interested in morphing the grid with randomness while also having an image interact with the grid. How do I go about designing varying cells and joining them together as a grid image? Can I use the random(); with (TRIANGLE\_STRIP),(QUAD\_STRIP) to create a variation or would line() be more successful in getting to following results pictured?

![f29b0ec3811fbc1e82188a290247f10f6e903ac0_2_484x500](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/9/6/96719787a81b801e66d30c0383d6e1d688e6e4a5.png)

 ![f3a6942792ce70e8fc9f334856b79aaba7f7ab9f_2_696x1000](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/6/0/6096ea9c24bfed86be482159e141a85ac45c8696.jpeg)  
 ![64c2ea6bdec8d0bd47b604089482b3473906407d_2_1000x1000](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/1/6/166973b526b2930c367e1c3229076098960945f4.jpeg)  
 ![a741e8f85b42611da6ed13f29844f66ec915cdd3_2_996x1000](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/2/7/27f432c5a8d5cb625cbfeac89e083c2f7fd5e383.jpeg)

I have tried the following code, but I can’t seem to get the visual results above.

```auto
// a class to representing a point on our grid.
// This should/would/could be done better by defining it as faces (of a triangle mesh).
// but would it keep as simple as possible 
class GridPoint {
  float x, y, v;
  public GridPoint(float px, float py, float pv) {
    x = px; // x-pos of the grid point
    y = py; // y-pos of the grid point
    v = pv; // height of the grid point
  }
}

//helper variables
float halfWidth, halfHeight;
boolean mode = false;
// storage of out grid
int rows, cols;
GridPoint[][] grid;
// image used for texture and heightmap
PImage img;

void setup() {
  size(980, 980, P3D); //OPENGL?
  noLoop();
  frameRate(1);
  smooth(8);
  halfWidth = width/2.;
  halfHeight = height/2.;
  initGrid(11.);
  // use textureMode IMAGE as the grid is not normalized
  textureMode(IMAGE);
}

void initGrid(float scl) {
  // load the image, used for texture and heightmap.
  // usually more than one picture will be used. One for heightmap, one for normalmap and one with the texture.
  // for simplicity it has the same size than our grid to not make the code more math intensive.
  // to get this work our image is somehow a bit blurred (like noise is), otherwise the mesh isn't smooth enough
  img = loadImage("gradient888.jpg");
  img.loadPixels();
  img.resize(980,980);
  // initialize our gridpoints
  rows = floor(height/scl);
  cols = floor(width/scl);
  grid= new GridPoint[rows][cols];
  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      int sx = floor(x*scl);
      int sy = floor(y*scl);
      // set x and y coordinates (center origin) and the height of the current point.
      // height is the normalized brightness value [0..1] of the pixel color from the image.
      // Subtract 0.5 to align it to center [-0.5..0.5]
      // scaling it by 50, so the range is [50.0*(-0.5)..50.0*(0.5)]
      grid[y][x] = new GridPoint(-halfWidth+sx+scl/2, -halfHeight+sy+scl/2, 200.*(brightness(img.get(sx, sy))/255-1.0));
    }
  }
}

void draw() 
{
    background(0);
  
  // set the origin to the center of the screen, and move it 400px far away on z-axis
  translate(halfWidth, halfHeight, 0.05); // zoom in (lower numbers) zoom out (higher numbers around 200)
  

  // switch between mesh and texured mode
  //if (frameCount % int(TAU*100.) == 0) {
  // mode = !mode;
  //}

  if (mode) 
  {
    //if textured mode no strokes and a light from viewpoint to object
    noStroke();
    directionalLight(255, 255, 255, 0, 0, -1);
  } else {
    // if mesh mode only show strokes
    noFill();
    stroke(250);
    strokeWeight(1.5);
    smooth(8);
    
  }

  // apply the rotation after lighting, otherwhile the light gets also rotated, which we not want.
  // tipping 30degree back on X-axis
  //rotateX(radians(30));
  // tipping left/right a bit per frame from -PI/4 - +PI/4 on Y-axis
  //rotateY(sin(frameCount/100.)*QUARTER_PI);

  // build the surface/terrain by triangle strips to display it
  for (int y = 0; y < rows-1; y ++) 
  {
    //beginShape (TRIANGLE_STRIP); // or (TRIANGLE_STRIP),(QUAD_STRIP), 
    int selector = int(random(4));
  
  if (selector == 0) {
    beginShape(TRIANGLE_STRIP);
   } else if (selector == 1) {
    beginShape(QUAD_STRIP);
   } else if (selector == 2) {
    beginShape(LINES);
   } else if ( selector == 3) {
    beginShape(QUAD_STRIP);
   } else if ( selector == 4) {
    beginShape(QUAD_STRIP);
   } 
   
    if (mode) {
      // on textured mode set the texture
      texture(img);
    }
    // common triangle strips
    for (int x = 0; x < cols; x++) {
      GridPoint ca = grid[y][x];
      GridPoint cb = grid[y+1][x];
      vertex(ca.x, ca.y, ca.v, ca.x+halfWidth, ca.y+halfHeight);
   
      if (mode) {
        // on textured mode we need to set the normal vector, so the light knows how to behave on hittng the surface
        // usually there are better calculation than this cheap hack
        // comment it out to see the difference if normals are messed up
        PVector na = new PVector(ca.x-cb.x, ca.y-cb.y, 0).sub(new PVector(ca.x-cb.x, ca.y-cb.y, 1)).normalize();
        normal(na.x, na.y, na.z);
      }
      vertex(cb.x, cb.y, cb.v, cb.x+halfWidth, cb.y+halfHeight);
      if (mode) {
        // on textured mode we need to set the normal vector, so the light knows how to behave on hittng the surface
        // usually there are better calculation than this cheap hack
        // comment it out to see the difference if normals are messed up
        PVector nb = new PVector(cb.x-ca.x, cb.y-ca.y, 0).sub(new PVector(cb.x-ca.x, cb.y-ca.y, 1)).normalize();
        normal(nb.x, nb.y, nb.z);
        }
      }
    endShape();
    }

```

This is my result with my current code

 ![72693da14d7e9ef07605514e67c2b81c96df04d0_2_1006x1000](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/3/0/3012516a60511bcf27e53aff99e7ee01289ff44e.jpeg)

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [December 13, 2022, 10:01am UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/2 "2022-12-13T10:01:43Z")

</div>

Hi @asymmetric,

> [@asymmetric](#):
>
> I’m interested in morphing the grid with randomness while also having an image interact with the grid.

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)

> [@asymmetric](#):
>
> Can I use the random(); with (TRIANGLE\_STRIP),(QUAD\_STRIP) to create a variation or would line() be more successful in getting to following results pictured?

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

```processing
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();
}

```

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/3/f/3f4d5f3118239dc88bf66c8692a0aa732e00ee7a.png)

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 😇

```processing
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! 😉

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 13, 2022, 3:41pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/3 "2022-12-13T15:41:55Z")

</div>

Thank you @Joseph!! How do I go about connecting my image to the above code?

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [December 13, 2022, 3:52pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/4 "2022-12-13T15:52:04Z")

</div>

> [@asymmetric](#):
>
> How do I go about connecting my image to the above code?

This is your next assignment ahah! 😉

If you are not familiar with the concepts I used above and image manipulation, make sure to follow the [Processing tutorials](https://processing.org/tutorials/), read the [reference](https://processing.org/reference) and document yourself

- How do I load an image using Processing?
- How do I read pixels?
- How do I drive each vertex height from the pixels of an image?

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 13, 2022, 3:54pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/5 "2022-12-13T15:54:49Z")

</div>

Okay, Joseph! Here I go… I may have more questions today!

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 13, 2022, 4:17pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/6 "2022-12-13T16:17:40Z")

</div>

My understanding is that I need to include the following code to create the height map with the variation grid design that you provided. With that being said, I am having trouble connecting the code provided to the following vertex height/ image reading.

```auto
//helper variables
float halfWidth, halfHeight;
boolean mode = false;
// storage of out grid
int rows, cols;
GridPoint[][] grid;
// image used for texture and heightmap
PImage img;

void setup() {
  size(980, 980, P3D); 
  noLoop();
  frameRate(1);
  smooth(8);
  halfWidth = width/2.;
  halfHeight = height/2.;
  initGrid(11.);
  // use textureMode IMAGE as the grid is not normalized
  //textureMode(IMAGE);
}

void initGrid(float scl) {
  // load the image, used for texture and heightmap.
  // usually more than one picture will be used. One for heightmap, one for normalmap and one //with the texture.
  // for simplicity it has the same size than our grid to not make the code more math intensive.
  // to get this work our image is somehow a bit blurred (like noise is), otherwise the mesh //isn't smooth enough
  img = loadImage("gradient888.jpg");
  img.loadPixels();
  img.resize(980,980);
  // initialize our gridpoints
  rows = floor(height/scl);
  cols = floor(width/scl);
  grid= new GridPoint[rows][cols];
  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      int sx = floor(x*scl);
      int sy = floor(y*scl);
      // set x and y coordinates (center origin) and the height of the current point.
      // height is the normalized brightness value [0..1] of the pixel color from the image.
      // Subtract 0.5 to align it to center [-0.5..0.5]
      // scaling it by 50, so the range is [50.0*(-0.5)..50.0*(0.5)]
      grid[y][x] = new GridPoint(-halfWidth+sx+scl/2, -halfHeight+sy+scl/2, 200.*(brightness(img.get(sx, sy))/255-1.0));
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 13, 2022, 4:20pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/7 "2022-12-13T16:20:36Z")

</div>

> [@asymmetric](#):
>
> `void initGrid(float scl) {`

After inserting my function void initGrid(float scl), what do I need to update? GridPoint no longer is the name of the class, so I will replace that with Grid?

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 14, 2022, 6:24pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/8 "2022-12-14T18:24:41Z")

</div>

![f3a6942792ce70e8fc9f334856b79aaba7f7ab9f_2_696x1000](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/6/0/6096ea9c24bfed86be482159e141a85ac45c8696.jpeg)

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 14, 2022, 9:40pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/9 "2022-12-14T21:40:38Z")

</div>

Hi @josephh ! I’m trying to figure out how to include an image to interact with the grid you created, but I don’t know where to start… Can you help me?

This is what I have so far!

```auto
int borderGap = 5;
int resolution = 50;
int maxHeight = 0;

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(2);

    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(1);
    stroke(#0BFF00);

    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();
  }
}

   void initGrid(float scl) {
  // load the image, used for texture and heightmap.
  // usually more than one picture will be used. One for heightmap, one for normalmap and one //with the texture.
  // for simplicity it has the same size than our grid to not make the code more math intensive.
  // to get this work our image is somehow a bit blurred (like noise is), otherwise the mesh //isn't smooth enough
  img = loadImage("gradient888.jpg");
  img.loadPixels();
  img.resize(1000,1000);
  // initialize our gridpoints
  rows = floor(height/scl);
  cols = floor(width/scl);
  grid= new Grid[rows][cols];
  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      int sx = floor(x*scl);
      int sy = floor(y*scl);
      // set x and y coordinates (center origin) and the height of the current point.
      // height is the normalized brightness value [0..1] of the pixel color from the image.
      // Subtract 0.5 to align it to center [-0.5..0.5]
      // scaling it by 50, so the range is [50.0*(-0.5)..50.0*(0.5)]
      grid[y][x] = new GridPoint(-halfWidth+sx+scl/2, -halfHeight+sy+scl/2, 200.*(brightness(img.get(sx, sy))/255-1.0));
    }
  }
}

  

Grid grid;

void setup() {
  size(1000, 1000, 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();
}

```

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [December 15, 2022, 9:48am UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/10 "2022-12-15T09:48:55Z")

</div>

Sorry for the delay! 😉

Try to solve this:

- In the code I posted, where are grid points initialized? What are the values given to the `x`, `y`, `z` coordinates? Where is the height value computed? How do you replace that with the brightness of your image?

- It’s not just a matter of adding your function to the `Grid` class that will work out of the box. Try to understand how classes and methods work.

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 15, 2022, 3:38pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/11 "2022-12-15T15:38:13Z")

</div>

The height is calculated by

```auto

int maxHeight = 70; /// Height brightness 

```

And the X,Y, Z

```auto

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

```

Are the following instance variables X and Y?

```auto

int borderGap = 60; // zoom in or out 
int resolution = 10; // grid cell and row size

```

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 15, 2022, 3:39pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/12 "2022-12-15T15:39:38Z")

</div>

I’m still feeling confused… Im thankful for your hep and guidance!

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [December 15, 2022, 4:31pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/13 "2022-12-15T16:31:31Z")

</div>

> [@asymmetric](#):
>
> Are the following instance variables X and Y?
> 
> ```auto
> int borderGap = 60; // zoom in or out 
> int resolution = 10; // grid cell and row size
> 
> ```

No, these are global variables meaning they are accessible everywhere in the code (inside functions, loops… and more generally any blocks).

```processing
int globalVariable = 0;

void example() {
  int localVariableToTheExampleFunction = 1;
  println(globalVariable); // Accessible here
}

example(); // Prints 0
println(localVariableToTheExampleFunction); // Error: not defined in this scope

```

This is the notion of [scope](https://en.wikipedia.org/wiki/Scope_(computer_science)) in computer science.

> [@asymmetric](#):
>
> `int maxHeight = 70; /// Height brightness `

This is a common practice to put global variables at the top of your program so modifying and reading them is easy. In this case, I am just declaring a variable that controls the maximum height that points can have using the `z` coordinate (pointing from you from the window point of view).

You need to understand how object oriented programming works (using classes with the `class`) keyword. See a previous message I did on the subject:

> [@Problems with my mini game](https://discourse.processing.org/t/problems-with-my-mini-game/21949/2):
>
> Hi, Welcome to the community! slight_smile Before trying to solve your problem, you are facing a well known problem where the structure of your code is actually describing [object oriented programming](https://en.wikipedia.org/wiki/Object-oriented_programming) : So object oriented programming is a way to structure your code by using objects to model the data that your are manipulating. In this special case, your are creating Balls, and a Ball is described as : a position (x and y coordinates on the screen) a speed (described as a vector, xDir and y…

* * *

To summarize, I am using a `Grid` class that describes the grid you want to display. It has a `points` attribute which is a 2D array of [PVector](https://processing.org/reference/PVector.html) (which is itself a class holding up to three coordinates `x`, `y`, `z`).

This is perfect since we want to handle 3D points organized in a grid (rows and columns).

A class has a constructor, it’s a special “method” with some parameters used to initialize the object (in this case the Grid):

```processing
class Grid {
  Grid(int resolution, int borderGap) {
    // Initialize the grid here (mainly point coordinates)
  }
}

```

Try to read the code and understand what each part does before trying to copy paste code at some places. 😉

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 15, 2022, 4:40pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/14 "2022-12-15T16:40:08Z")

</div>

I think I need an example for how to connect an image height map to the code above…

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [December 15, 2022, 4:54pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/15 "2022-12-15T16:54:52Z")

</div>

Learning how to code is a process, either you don’t want to learn or you want me to give you the full solution to your issue (assignment?).

I don’t want to be rude but I gave you enough resources for you to look at them and understand how the different pieces fit together. So go for it! 😉

If you still don’t understand the above code, try to start with a simpler example and build up to a more complex state.

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 15, 2022, 5:13pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/16 "2022-12-15T17:13:03Z")

</div>

I really do want to learn but I’m hitting a wall interconnecting the image heighmap aspect. I completely understand where you are coming from, but I tend to learn from examples where my misunderstandings are. I just completed an OOP JavaScript class but I’m getting lost in how to connect the variables or the renaming of the variables…

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 15, 2022, 8:50pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/17 "2022-12-15T20:50:26Z")

</div>

Is this where you initialized the Grid Points?

```auto
// 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;
      }
    }
  }

```

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [December 15, 2022, 10:16pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/18 "2022-12-15T22:16:25Z")

</div>

Yes, so you need to use the image pixel information (it can be the brightness or something else) and put that into the height of each point

---

<div class="post-metadata">

**Author:** ![asymmetric](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/asymmetric/32/16577_2.png) [@asymmetric](https://discourse.processing.org/u/asymmetric)\
**Post date:** [December 15, 2022, 10:28pm UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/19 "2022-12-15T22:28:31Z")

</div>

That’s the part that I get confused with…

```auto
      points[I][j] = new PVector(-resolution+x, -resolution+y, 200.*(brightness(img.get(x, y))/ borderGap));

```

This is my code right now…

```auto
//GLOBAL VARIABLES
PImage img;

int borderGap = 5;
int resolution = 70;
int maxHeight = 0;

Grid grid;

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

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

  grid = new Grid(resolution, borderGap);
  
  smooth(8);
}

void draw() {
  background(0);

  grid.display();

  noLoop();
}

/**
 * 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
class Grid {
  //INSTANCE VARIABLES
  PVector[][] points;
  boolean[][] diagonals;

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

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

    img = loadImage("b.png");
    img.loadPixels();
    img.resize(1000,1000);
    // 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(2);
    stroke(#0BFF00);

    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();
  }
}

```

---

<div class="post-metadata">

**Author:** ![josephh](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/josephh/32/210_2.png) [@josephh](https://discourse.processing.org/u/josephh)\
**Post date:** [December 16, 2022, 8:49am UTC](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135/20 "2022-12-16T08:49:49Z")

</div>

> [@asymmetric](#):
>
> That’s the part that I get confused with…
> 
> ` points[I][j] = new PVector(-resolution+x, -resolution+y, 200.*(brightness(img.get(x, y))/ borderGap));`

Here try to understand what each part does:

- What does `img.get(x, y)` returns?
- What does `brightness(...)` returns?

In my code I have:

```processing
float pointHeight = random(maxHeight);
points[i][j] = new PVector(x, y, pointHeight);

```

So the height of each point is a random value between `0` and `maxHeight`. This is not what you want so you should remove that. You want the height to depend on the brightness of the pixel on your image.

Hopefully that makes sense 😉

[Next page](https://discourse.processing.org/t/creating-variation-in-grid-with-random-image/40135.md?page=2)
