Truchet pattern 3D height map from blurred image

please format code with </> button * homework policy * asking questions

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…

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

please help @mnse :pray:

Hi @asymmetric,

still the same used in earlier post.

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

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

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

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

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

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

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

dummy3

1 Like

Thank you soooooo much, @mnse!!! You made my day!!! Happy Holidays! :christmas_tree: :christmas_tree: :christmas_tree: :christmas_tree: :christmas_tree: :christmas_tree: :christmas_tree: :christmas_tree: :christmas_tree: :stars: :stars: :stars: :stars: :stars: :stars: :stars: :stars: :stars: :stars: :stars: :stars: :stars: :stars: :stars:

1 Like


Thank you @mnse !! Merry Christmas!!

1 Like