Maintaining same visual angle of stacked layers

What I’m trying to achieve is cross-sections of a 3D noise cube. The look I’m going for is like this:

But what I’m getting is more like this given the default perspective of the environment giving the conical perspective:
3d_layers_perspective

This is the result I’m getting:

The first thing I tried was using ortho(), but that doesn’t quite achieve the same look of having some kind of depth of field. Just flattens it like this:

I’ve also tried changing them from layered across the X to the Z axis and rotating them but they then have different sizes because it is making the ones lower on the Z axis smaller.

I’ve also tried to find a hack where I change the rotation for each depending on their screen location, but I can’t get a consistent formula that works to make the layers appear at a consistent angle across all the board.

Would changing the position of the camera to the left side of the screen achieve the effect? I’ve never played with that function. Beyond that, I’m not sure how else to tackle this problem. Would appreciate any suggestions. Bonus points if anyone has a way of making each layer have a higher strokeWeight() border so when the layers overlap, they don’t just blend into each other.

Full code:

color bg = color(18,18,18);
color clrA = color(57,190,227);
color clrB = color(142,57,227);

ArrayList<Layer> noiseLayers;
int numIters = 6;
float layerDiff = 0.2;
float layerSpace = 80;
int numCols, numRows;
float boxSize = 15;
int marginW = 80;
int marginH = 50;
int canvasW, canvasH;
float halfCanvasW, halfCanvasH;
float seedVal = random(0,1000000);
float yRot = 2.25;

void setup() {
  size(1600, 850, P3D);
  background(bg);
  
  canvasW = width - (marginW*2);
  canvasH = height - (marginH*2);
  halfCanvasW = canvasW / 2;
  halfCanvasH = canvasH / 2;
  numCols = int(canvasW / boxSize);
  numRows = int(canvasH / boxSize);
  numCols = numRows;
  noiseLayers = new ArrayList<Layer>();
  makeLayers();
  
  smooth(8);
  ortho();
}

void draw() {
  background(bg);
  
  for(Layer l : noiseLayers){
    l.render();
  }
}

void makeLayers() {
  for(int i=0; i<numIters; i++){
    float xPos = width/2 + marginW - (floor(numIters/2) * (canvasW / numIters)) + (i * (canvasW / numIters));
    float zOff = i * layerDiff;
    color clr = lerpColor(clrA, clrB, map(i, 0, numIters, 0, 1));
    float terrain[][] = new float[numCols][numRows];
    float yOff = 0.0;
    for (int y=0; y<numRows; y++) {
      float xOff = 0.0;
      for (int x=0; x<numCols; x++) {
        terrain[x][y] = map(noise(xOff, yOff, zOff), 0, 1, -30, 30);
        xOff += 0.3;
      }
      yOff += 0.3;
    }
    noiseLayers.add(new Layer(xPos, zOff, clr, terrain));
  }
}

class Layer {
  float layerPos;
  float zOff;
  color colorSel;
  float[][] terrain;
  
  Layer(float thePos, float theZ, color theColor, float[][]thePlane) {
    layerPos = thePos;
    zOff = theZ;
    colorSel = theColor;
    terrain = thePlane;
  }
  
  void update() {
    //make changes as needed
  }
  
  void render() {
    strokeWeight(1);
    stroke(colorSel);
    fill(bg);
    //noFill();
    pushMatrix();
    translate(layerPos, height/1.35);
    rotateY(-PI/yRot);
    rotateZ(PI/5);
    translate(-(canvasW/2), -(canvasH/2));
    for(int y=0; y<numRows-1; y++){
      beginShape(QUAD_STRIP);
      for(int x=0; x<numCols; x++){
        vertex(x*boxSize, y*boxSize, terrain[x][y]);
        vertex(x*boxSize, (y+1)*boxSize, terrain[x][y+1]);
      }
      endShape();
    }
    popMatrix();
  }
}
1 Like

I added the following to the draw function:
camera(width/14, height/2, (height/2.0) / tan(PI*30.0 / 180.0), width/4, height/2, 0, 0, 1, 0);

Which gives the result of:

It’s closer, but the ones to the right still appear “flattter” / less angled (as well as smaller) and don’t convey the definition of the noisy layer like the ones on the left do.

1 Like

One approach might be PGraphics

When you have one PGraphics with same angle for each slide you are good.

There might arise difficulties when you display them, maybe you need some transparency there.

2 Likes

In this approach, I would draw each layer at center screen, then save as PGraphics, and draw it elsewhere on the screen in the main loop? That sounds like it could work. I’ll give it a shot a little later.

No need to draw to the screen in the first place.

you can draw directly to the PGraphics

you can even have an array of PGraphics


Here is an example

As you can see the position of the pg doesn’t change the angle of the box in the pg.

PGraphics pg ;

// -------------------------------------------------------------------------------------------------------------------------

void setup() {
  size(1900, 1000, P3D);
  makePG();
}

void draw() {
  background(10);
  image(pg, mouseX, mouseY);
}

// -----------------------------------------------------------------------------------------------------------------------------------

void makePG() {

  pg = createGraphics(400, 400, P3D);

  pg.beginDraw();
  pg.background(100);

  pg.fill(255, 0, 0);
  pg.stroke(255);

  pg.lights();
  pg.translate(pg.width/2+16, pg.height/2-162, 0);

  pg.box(66, 12, 66);

  pg.endDraw();
}

2 Likes

new version, showing the same pg 10 times,
maintaining visual angle

PGraphics pg;

// -------------------------------------------------------------------------------------------------------------------------

void setup() {
  size(1900, 1000, P3D);
  makePG();
}

void draw() {
  background(10);

  translate(mouseX, mouseY);
  for (int i=0; i<10; i++) {
    image(pg, 0, 12+i*66);
  }
}

// -----------------------------------------------------------------------------------------------------------------------------------

void makePG() {

  pg = createGraphics(400, 99, P3D);

  pg.beginDraw();
  pg.background(10);
  pg.lights();

  pg.fill(255, 0, 0);
  pg.stroke(255);

  pg.pushMatrix();
  pg.translate(pg.width/2+22, 1+33*1, 0);
  pg.box(66, 12, 66);
  pg.popMatrix();


  pg.endDraw();
}
//

1 Like

Reconfigured the code to put it into a PGraphic and it works for the most part. Here’s a sample without the rotation on the Z axis:

However, when I uncomment this line:
plane.rotateZ(PI/5);
I get some clipping that I can’t figure out how to account for.

It looks like it’s lopping off the top part of the rotated planes as if they rotate out of the canvas. But I don’t know how to define the createGraphics() size to accommodate the rotation. Even when I double the width and height, it still lops it off.

The other issue has to do with the fill and graphic transparency. The plane.fill() command to make sure the plane don’t bleed into each other and the plane.clear() command to put transparency of overall PGraphic do not appear to be working. And it isn’t that they cancel each other out as I turn them on and off to the same effect.

Full code:

import processing.svg.*;
boolean makeSVG = false;
import processing.pdf.*;
boolean makePDF = false;
String docBase = "noise_layers";
String docName = "";

color bg = color(18,18,18);
color clrA = color(57,190,227);
color clrB = color(142,57,227);

ArrayList<Layer> noiseLayers;
int numIters = 9;
float layerDiff = 0.2;
float layerSpace = 80;
int numCols, numRows;
int boxSize = 15;
int xSize, ySize;
int marginW = 80;
int marginH = 50;
int canvasW, canvasH;
float halfCanvasW, halfCanvasH;
float seedVal = random(0,1000000000);
float yRot = 2.25;

void setup() {
  size(1600, 850, P3D);
  background(bg);
  
  canvasW = width - (marginW*2);
  canvasH = height - (marginH*2);
  halfCanvasW = canvasW / 2;
  halfCanvasH = canvasH / 2;
  numCols = int(canvasW / boxSize);
  numRows = int(canvasH / boxSize);
  numCols = numRows;
  xSize = numCols * boxSize;
  ySize = numRows * boxSize;
  noiseLayers = new ArrayList<Layer>();
  makeLayers();
  
  smooth(8);
}

void draw() {
  background(bg);
  
  for(Layer l : noiseLayers){
    l.render();
  }
}

void makeLayers() {
  for(int i=0; i<numIters; i++){
    float xPos = width/2 - ((layerSpace * numIters) / 2) + (layerSpace / 2) + (i * layerSpace);
    float zOff = i * layerDiff;
    float yOff = 0.0;
    color clr = lerpColor(clrA, clrB, map(i, 0, numIters, 0, 1));
    float terrain[][] = new float[numCols][numRows];
    for(int y=0; y<numRows; y++){
      float xOff = 0.0;
      for(int x=0; x<numCols; x++){
        terrain[x][y] = map(noise(xOff, yOff, zOff), 0, 1, -30, 30);
        xOff += 0.3;
      }
      yOff += 0.3;
    }
    
    PGraphics plane = createGraphics(width, height, P3D);
    plane.beginDraw();
    plane.strokeWeight(1);
    plane.stroke(clr);
    plane.fill(bg);
    plane.clear();
    plane.pushMatrix();
    plane.translate(width/2, height/2);
    plane.rotateY(-PI/yRot);
    plane.rotateZ(PI/5);
    plane.translate(-(canvasW/2), -(canvasH/2));
    for(int y=0; y<numRows-1; y++){
      plane.beginShape(QUAD_STRIP);
      //plane.strokeWeight(1);
      //plane.stroke(clr);
      //plane.fill(bg);
      for(int x=0; x<numCols; x++){
        plane.vertex(x*boxSize, y*boxSize, terrain[x][y]);
        plane.vertex(x*boxSize, (y+1)*boxSize, terrain[x][y+1]);
      }
      plane.endShape();
    }
    plane.popMatrix();
    plane.endDraw();
    
    noiseLayers.add(new Layer(xPos, zOff, clr, terrain, plane));
  }
}

class Layer {
  float layerPos;
  float zOff;
  color colorSel;
  float[][] terrain;
  PGraphics plane;
  
  Layer(float thePos, float theZ, color theColor, float[][] theLayer, PGraphics thePlane) {
    layerPos = thePos;
    zOff = theZ;
    colorSel = theColor;
    terrain = theLayer;
    plane = thePlane;
  }
  
  void update() {
    //make changes as needed
  }
  
  void render() {
    pushMatrix();
    translate (layerPos, 0, -200);
    image(plane, -width/2, 0);
    popMatrix();
  }
}

Wild guess

But can you implement this in the pg

// Tools 

void avoidClipping() {
  // avoid clipping (at camera): 
  // https : // 
  // forum.processing.org/two/discussion/4128/quick-q-how-close-is-too-close-why-when-do-3d-objects-disappear
  perspective(PI/3.0, (float) width/height, 1, 1000000);
}//func