# Truchet pattern 3D height map from blurred image

**URL:** https://discourse.processing.org/t/truchet-pattern-3d-height-map-from-blurred-image/39492
**Category:** Coding Questions
**Created:** [October 29, 2022, 5:12pm UTC](https://discourse.processing.org/t/truchet-pattern-3d-height-map-from-blurred-image/39492 "2022-10-29T17:12:16Z")
**Posts on this page:** 6
**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: [October 29, 2022, 5:12pm UTC](https://discourse.processing.org/t/truchet-pattern-3d-height-map-from-blurred-image/39492/1 "2022-10-29T17:12:16Z")

</div>

> please format code with \</\> button \* [homework policy](https://discourse.processing.org/faq/#homework) \* [asking questions](https://discourse.processing.org/t/2147)

I would like to create a 3D heightmap of a blurred image out of the following truchet pattern grid (via “Processing: Creative Coding and Generative Art in Processing 2”), but I am running into a wall…

```auto
int tileSize = 24;
int rows = 35;
int cols = 35;
Tile[][] tiles = new Tile[rows][cols];

void setup(){
  size(800,800); // (tileSize*rows, tileSize*cols);
  smooth();
  background(255);
  
  for (int i = 0; i < rows; i++){
    for (int j = 0; j < cols; j++){
      tiles[i][j] = new Tile(j*tileSize, i*tileSize, tileSize);
      tiles[i][j].display();
    }
  }
}

class Tile{
  int sz;
  int x,y;
  int orient;
  
Tile(int x, int y, int w){
  this.x = x;
  this.y = y;
  sz = w;
  orient = int (random(0,3));
}

void display(){
  pushMatrix(); 
  translate(x,y);
  translate(sz/2, sz/2);
  rotate(orient*PI/2);
  translate(-sz/2,-sz/2);
  fill(0);
  triangle(sz,0,sz,sz,0,sz);
  popMatrix();
  }
}

```

 ![IMG_5967](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/7/9/79a842e51eb3d487c3f958687b705ab5ab1d829b.jpeg)

please help @mnse 🙏

---

<div class="post-metadata">

### Author: ![mnse](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/mnse/32/16520_2.png) [@mnse](https://discourse.processing.org/u/mnse)
#### Post date: [October 31, 2022, 12:40pm UTC](https://discourse.processing.org/t/truchet-pattern-3d-height-map-from-blurred-image/39492/2 "2022-10-31T12:40:25Z")

</div>

Hi @asymmetric,

still the same used in earlier post.

> [@3D Perlin noise in Processing](https://discourse.processing.org/t/3d-perlin-noise-in-processing/37770/15):
>
> Hi again, Well, as the day is slowly coming to an end and I’ve had some thoughts about whether to post or not, I’ve come to the decision that I will post it after all. There are many pros and cons that could be listed, but none of them weigh so heavily that there would be a right or wrong. Reasons are … My code is just one of many examples and is far from an all-encompassing implementation. There are many things that can be worked out in addition to this on the topic. I’ve now added lots of…

> [@How to link grid to image as a height map](https://discourse.processing.org/t/how-to-link-grid-to-image-as-a-height-map/38254/3):
>
> Hi @asymmetric, just for the sake of completness … I extended to 3D Removed all the mouse picking stuff, as picking in 3D is another topic and would go beyond the scope here… Cheers — mnse float scl = 8.; int rows, cols; int halfWidth; int halfHeight; boolean mode = true; GridPoint[][] grid; PImage img; class GridPoint { PVector position; PVector oposition; PVector uv; boolean locked; float phase; public GridPoint(float x, float y, float z, float u, float v, boolean plocked) {…

Look at it again and try to figure out what’s to do…  
As a Hint: read the blurred image into a buffer (maybe convert to grayscale beforehand), and map ie brightness from black to white (-1 to 1) and apply it to the corresponding z-coords (maybe multiplied with a factor, ie. 50.).

Cheers  
— mnse

---

<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 22, 2022, 8:33pm UTC](https://discourse.processing.org/t/truchet-pattern-3d-height-map-from-blurred-image/39492/3 "2022-12-22T20:33:12Z")

</div>

Hi @mnse! I have the following code. How do I fill in the following grid with truchet patterns?

```auto
//GLOBAL VARIABLES
PImage img;

int borderGap = 10;
int resolution = 100;
//int maxHeight = 0;

Grid grid;

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

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

  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("gradient888.jpg");
    img.loadPixels();
    img.resize(100,100);
    // 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 = 200 *(brightness(img.get(i,j))/ 255-0.8);
        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(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 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();
  }
}

```

 ![Screen Shot 2022-12-22 at 12.28.29 PM](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/5/8/581cbc503450c79adad7244616d9d6ca69679f88.jpeg)

 ![Screen Shot 2022-12-20 at 12.11.44 PM](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/b/6/b6b9da1934457744204a19d48fd0a09527b34898.jpeg)

```auto
int tileSize = 24;
int rows = 35;
int cols = 35;
Tile[][] tiles = new Tile[rows][cols];

void setup(){
  size(800,800); // (tileSize*rows, tileSize*cols);
  smooth();
  background(255);
  
  for (int i = 0; i < rows; i++){
    for (int j = 0; j < cols; j++){
      tiles[i][j] = new Tile(j*tileSize, i*tileSize, tileSize);
      tiles[i][j].display();
    }
  }
}

class Tile{
  int sz;
  int x,y;
  int orient;
  
Tile(int x, int y, int w){
  this.x = x;
  this.y = y;
  sz = w;
  orient = int (random(0,3));
}

void display(){
  pushMatrix(); 
  translate(x,y);
  translate(sz/2, sz/2);
  rotate(orient*PI/2);
  translate(-sz/2,-sz/2);
  fill(0);
  triangle(sz,0,sz,sz,0,sz);
  popMatrix();
  }
}

```

---

<div class="post-metadata">

### Author: ![mnse](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/mnse/32/16520_2.png) [@mnse](https://discourse.processing.org/u/mnse)
#### Post date: [December 23, 2022, 10:50am UTC](https://discourse.processing.org/t/truchet-pattern-3d-height-map-from-blurred-image/39492/4 "2022-12-23T10:50:28Z")

</div>

Hi @asymmetric,

As you need the colors strictly separated in this case the TRIANGLE\_STRIP won’t work due to the kind of coloring behaviour for shared vertices. I’ve changed to draw the triangles separately so they have their own color each. See code below …

Cheers  
— mnse

```auto
import peasy.*;

//GLOBAL VARIABLES
PImage img;

int borderGap = 10;
int resolution = 20;
//int maxHeight = 0;

Grid grid;
PeasyCam cam;

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

void setup() {
  size(500, 500, P3D);
  cam = new PeasyCam(this,600);
  //pixelDensity(1);

  grid = new Grid(resolution, borderGap);

  smooth(8);
}

void draw() {
  background(0);
  translate(-width/2, -height/2 , 0);
  //rotateY(frameCount/25.);
  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;
  boolean[][] colorswitch;

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

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

    //img = loadImage("gradient888.jpg");
    //img.loadPixels();
    //img.resize(100,100);
    // 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 = 200.*noise(i*0.1,j*0.1);// 0;//200 *(brightness(img.get(i,j))/ 255-0.8);
        points[i][j] = new PVector(x, y, pointHeight);

        // Store diagonal info, with 1/2 flip
        diagonals[i][j] = random(1) < 0.5;
        colorswitch[i][j] = random(1) < 0.5;
      }
    }
  }

  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 displayTriangleStrips() {
    stroke(255);
    strokeWeight(1);
    noFill();

    for (int j = 0; j < resolution - 1; j++) {
      for (int i = 0; i < resolution - 1; i++) {
        PVector P1 = points[i][j];
        PVector P2 = points[i+1][j];
        PVector P3 = points[i+1][j+1];
        PVector P4 = points[i][j+1];
        noStroke();
        beginShape(TRIANGLES);
        if (diagonals[i][j]) {
          fill(colorswitch[i][j] ? color(255, 0, 0) : color(0, 0, 255));
          vertex(P4.x, P4.y, P4.z);
          vertex(P1.x, P1.y, P1.z);
          vertex(P2.x, P2.y, P2.z);
          fill(!colorswitch[i][j] ? color(255, 0, 0) : color(0, 0, 255));
          vertex(P4.x, P4.y, P4.z);
          vertex(P2.x, P2.y, P2.z);
          vertex(P3.x, P3.y, P3.z);
        } else {
          fill(colorswitch[i][j] ? color(255, 0, 0) : color(0, 0, 255));
          vertex(P1.x, P1.y, P1.z);
          vertex(P2.x, P2.y, P2.z);
          vertex(P3.x, P3.y, P3.z);
          fill(!colorswitch[i][j] ? color(255, 0, 0) : color(0, 0, 255));
          vertex(P1.x, P1.y, P1.z);
          vertex(P4.x, P4.y, P4.z);
          vertex(P3.x, P3.y, P3.z);
        }

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

```

 ![dummy2](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/9/e/9e97bfe9a24054f15d44ae5df178b7f3f0b24c1f.png)

EDIT: Simply add PeasyCam so you can see it in 3D. Heightmap is random as I don’t have you image.

![dummy3](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/b/e/be627014a4ecd26643d88a60c3853948608926c4.png)

---

<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 23, 2022, 5:41pm UTC](https://discourse.processing.org/t/truchet-pattern-3d-height-map-from-blurred-image/39492/6 "2022-12-23T17:41:56Z")

</div>

Thank you soooooo much, @mnse!!! You made my day!!! Happy Holidays! 🎄 🎄 🎄 🎄 🎄 🎄 🎄 🎄 🎄 🌠 🌠 🌠 🌠 🌠 🌠 🌠 🌠 🌠 🌠 🌠 🌠 🌠 🌠 🌠

---

<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 25, 2022, 3:33am UTC](https://discourse.processing.org/t/truchet-pattern-3d-height-map-from-blurred-image/39492/7 "2022-12-25T03:33:35Z")

</div>

![Screen Shot 2022-12-23 at 8.48.06 AM](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/d/9/d91217f6fce17cbc0d090235e5b7e2f7a5637061.jpeg)  
Thank you @mnse !! Merry Christmas!!
