3D image transform question

hi there! im recreating this effect : Login • Instagram
but my looks not very good.
this is my looks like:


I think that in the original video, where the gray value is high, It’s not that the height of boxes change, but more boxes are generated, how can i made that? Then I used sin() to control the switch of two pictures, but it’s not good, is there any other good choice?

My code:
<

PImage source1, source2;
PImage destination;
float t = 1;

void setup() {
  size(1000, 1000, P3D);
  source1 = loadImage("11.jpg");
  source2 = loadImage("22.jpg");
  destination = createImage(width, height, RGB);
}

void draw() {
  background(0);
  float tiles = 500;
  float tileSize = width/tiles;

  directionalLight(126, 126, 126, 1, -1, 0);
   directionalLight(126, 126, 126, 1, -1, 0);
  ambientLight(100, 100, 100);


  source1.loadPixels();
  source2.loadPixels();
  destination.loadPixels();
  t += 0.2;
  for (int x = 0; x < width; x++) {
    for (int y = 0; y < height; y++) {
      int loc = x + y * width;
      color c1 = source1.pixels[loc];
      color c2 = source2.pixels[loc];

      float d1 = brightness(c1);
      float d2 = brightness(c2);
      float d = map(cos(t), 0, 1, d1, d2);

      destination.pixels[loc] = color(d);
    }
  }
  //destination.updatePixels();

  push();
  translate(width/2, height/2);
  rotateY(map(mouseX, 0, width, -PI, PI));
  rotateX(map(mouseY, 0, height, PI, -PI));

  for (int x = 0; x < tiles; x++) {
    for (int y = 0; y < tiles; y++) {
      color c = destination.get(int(x * tileSize), int(y * tileSize));
      float b = map(brightness(c), 0, 255, 1, 0);
      float z = map(b, 0, 1, 100, -100);
      float wave = map(cos(radians(frameCount + z + z )), -1, 1, -2, 2);
      push();
      fill(255);
      translate(x * tileSize - width/2, y * tileSize - height/2, z * wave - 300);
      noStroke();
      box(tileSize * b, tileSize * b, tileSize * b * 10 );
      pop();
    }
  }
  pop();
}

hi! welcome to the forum!

please format your code with </> button so it’s easier to see and copy/paste. also if you can provide example images, that would be better.

what I see in Tim’s video is that when greyscale value is high (or low, I don’t know), the z position of the boxes change - plus, the sizes change at certain threshold. regarding your question with sin() as well, I think they are using easing functions to make smooth change. There are libraries like Ani but I found they are confusing so I adapted easing functions from processing-penner-easing/src at master · jesusgollonet/processing-penner-easing · GitHub

// adapted from https://github.com/jesusgollonet/processing-penner-easing/tree/master/src
float easeInOutLinear (float t) {
  float b = 0, c = 1, d = 1;
  return c*t/d + b;
}

float easeInOutQuad(float t) {
  float b = 0, c = 1, d = 1;
  if ((t/=d/2) < 1) return c/2*t*t + b;
  return -c/2 * ((--t)*(t-2) - 1) + b;
}

float easeInOutCubic (float t) {
  float b = 0, c = 1, d = 1;
  if ((t/=d/2) < 1) return c/2*t*t*t + b;
  return c/2*((t-=2)*t*t + 2) + b;
}

float easeInOutQuart(float t) {
  float b = 0, c = 1, d = 1;
  if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
  return -c/2 * ((t-=2)*t*t*t - 2) + b;
}

float easeInOutQuint (float t) {
  float b = 0, c = 1, d = 1;
  if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
  return c/2*((t-=2)*t*t*t*t + 2) + b;
}

void setup() {
  size(800, 800);
}

void draw() {
  background(0);
  float T = millis() * 0.001;
  float t = (T / 2) % 2;
  if (t > 1) t = 2 - t; // back and forth
  float ystep = height / 10;
  float r = 100;
  push();
  {
    translate(0, ystep);
    float x = easeInOutLinear(t);
    ellipse(x * width, 0, r, r);
    translate(0, ystep);
  }
  {
    translate(0, ystep);
    float x = easeInOutQuad(t);
    ellipse(x * width, 0, r, r);
    translate(0, ystep);
  }
  {
    translate(0, ystep);
    float x = easeInOutCubic(t);
    ellipse(x * width, 0, r, r);
    translate(0, ystep);
  }
  {
    translate(0, ystep);
    float x = easeInOutQuart(t);
    ellipse(x * width, 0, r, r);
    translate(0, ystep);
  }
  {
    translate(0, ystep);
    float x = easeInOutQuint(t);
    ellipse(x * width, 0, r, r);
    translate(0, ystep);
  }
  pop();

  push();
  translate(width / 2, 0);
  rectMode(CENTER);
  {
    translate(0, ystep);
    push();
    float x = easeInOutLinear(t);
    rotate(x * PI * 2);
    rect(0, 0, r, r);
    pop();
    translate(0, ystep);
  }
  {
    translate(0, ystep);
    push();
    float x = easeInOutQuad(t);
    rotate(x * PI * 2);
    rect(0, 0, r, r);
    pop();
    translate(0, ystep);
  }
  {
    translate(0, ystep);
    push();
    float x = easeInOutCubic(t);
    rotate(x * PI * 2);
    rect(0, 0, r, r);
    pop();
    translate(0, ystep);
  }
  {
    translate(0, ystep);
    push();
    float x = easeInOutQuart(t);
    rotate(x * PI * 2);
    rect(0, 0, r, r);
    pop();
    translate(0, ystep);
  }
  {
    translate(0, ystep);
    push();
    float x = easeInOutQuint(t);
    rotate(x * PI * 2);
    rect(0, 0, r, r);
    pop();
    translate(0, ystep);
  }
  pop();
}

you can see that the lower ones’ movements are more crisp and human like… note that you have to clamp the input values of easeInOut* always between 0 to 1.

Thank you very much for your answer! I will try your suggestions ! :wink:

Hnet.com-image
I’m so excited to share my results to u!
Finally I made this, not perfect but I think it’s enough cool, I can’t do it without your help! Much appreciated! :smiling_face_with_three_hearts:

1 Like