How to make my images spin around an ellipse in P3D?

Hey, guys. I recently learned about the peasycam library, thus how convenient and handy is, when it comes to mouse-driven camera rotation. So I tried to use the library in my recent project. The idea was to create a ring of 3 or more images (or planes with applied images as a texture) with the camera rotating around them.

I did my best for the most part and I succeeded in integrating the library within my sketch. However, I don’t know how to make my images spin around an invisible ring/ellipse. For example, I want to achieve an effect, similar to the one used in the following p5.js sketch, which I found while searching on openprocessing.org 3D Image Ring Sample - OpenProcessing To my regret, I am far away from understanding the p5.js syntax. So here is my code. Any ideas on how to fix it:

import peasy.*;

PeasyCam cam;

PImage img, img2, img3; 

void setup(){
  size(1920,1080,P3D); 
  
  cam = new PeasyCam(this, 500);
  cam.setMinimumDistance(50);
  cam.setMaximumDistance(5000);
  
  img = loadImage("1.jpg");
  img2 = loadImage("2.jpg");
  img3 = loadImage("3.jpg");
  
}
      
void draw(){
  rotateX(-.5);
  rotateY(-.5);
  background(0);
  pushMatrix();
  translate(CENTER,CENTER);
  
  imageMode(CENTER);
  img.resize(0,600);
  image(img,width/2,height/2);
  
  imageMode(CORNER);
  img2.resize(0,600);
  image(img2,width/9,height/18);
  
  imageMode(CORNER);
  img3.resize(0,600);
  image(img3,width/1.4,height/1.75);
  
  
  popMatrix();
}

P.S you can use whatever .jpg images you find. Just rename them to 1.jpg and 2.jpg Size doesn’t matter because they will be resized. Thanks in advance for any help you can rovide :blush:

Hi,

To start simple, let’s think about how we are going to do it in 2D.

We need a mathematical way to define the movement of our images and for this we have trigonometry.

Check this tutorial on the Processing website : Trigonometry Primer \ Processing.org

Check out this simple example :

// Dimensions of the circle
int diameter = 50;
float radius = diameter / 2.0;

// Angle increasing over time
float angle = 0;

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

void draw() {
  background(255);
  
  // Move to the center of the window
  translate(width / 2, height / 2);
  
  // Draw the big circle
  stroke(0);
  strokeWeight(1);
  circle(0, 0, diameter);
  
  // Compute the point location
  float px = cos(angle) * radius;
  float py = sin(angle) * radius;
  
  // Display the point
  stroke(255, 0, 0);
  strokeWeight(10);
  point(px, py);
  
  // Move forward
  angle += 0.05;
}

And we have a point rotating over a circle using the cos and sin functions :

rotate_circle

Now you said that you want the images to rotate over an ellipse but how do we define an ellipse?

Simply we can say that an ellipse is a circle with dimensions on x and y axis that are not equal :wink:

What if instead we say :

float px = cos(angle) * radiusX;
float py = sin(angle) * radiusY;

where radiusX and radiusY are the radius of the ellipse on the x and y axis.

Note that this is exactly what the parametric definition of an ellipse is (from the Wikipedia page on the ellipse):

Capture d’écran de 2021-03-23 01-21-04


Let’s do this :

// Dimensions of the ellipse
float radiusX = 45;
float radiusY = 20;

// Angle increasing over time
float angle = 0;

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

void draw() {
  background(255);
  
  // Move to the center of the window
  translate(width / 2, height / 2);
  
  // Draw the ellipse
  stroke(0);
  strokeWeight(1);
  ellipse(0, 0, radiusX * 2, radiusY * 2);
  
  // Compute the point location
  float px = cos(angle) * radiusX;
  float py = sin(angle) * radiusY;
  
  // Display the point
  stroke(255, 0, 0);
  strokeWeight(10);
  point(px, py);

  // Move forward
  angle += 0.05;
}

Which gives (two examples :wink: ):

rotate_ellipse_2 rotate_ellipse

Now this is just a matter of putting this in 3d since it’s a generalization of 2d but with one more axis.

You also need to find a way to move the images from their center and at different locations on the ellipse.

Have fun! :yum:

3 Likes

Hey, josephh. It’s nice to see you again here. Hope you are doing well and safe. :muscle: :innocent:

Thank you for providing all this information. I followed your guide and I am one step closer to reaching the wanted results. Besides, I am not sure if it is mathematically correct, but while playing around I found a way to scatter the images around the circle. Here is the updated version of my code with some notes:

import peasy.*;

PeasyCam cam;

PImage img;

float num_img = 10; //number of images

float dist = 1400; // distance between  the images and the center

float angle = radians (360 / num_img); //// angle between the circles and the center 

float offset = radians (190); 

float amp = 0.02; //can be used to amplify the speed of the rotation

void setup() {
  size (1920, 1080, P3D);

  cam = new PeasyCam(this, 500);
  cam.setMinimumDistance(500);
  cam.setMaximumDistance(5000);

  img = loadImage("3.jpg");
}

void draw () {
  background (0);

  for (int i = 1; i <= num_img; i++) {

    float x = sin(angle *i + offset) * dist + width/2;
    float y = cos(angle *i + offset) * dist + height/2;


    imageMode(CENTER);
    img.resize(0, 800);
    image(img, x, y);
  }


  offset = offset + amp;
}

I understand that when it comes to 3D transformations additionally, one more argument is required. However, I am not quite sure how to manipulate my image coordinates with this newly added Z-axis? As far as I know, the image function requires only 3 parameters by default (the img parameter specifying the source image which should be displayed and X and Y being the parameters that define the location) Which of them must be modified? How can I nest the Z-axis in my sketch?

Other than that, I wanted each image plane to display different photos, so I rewrote the code as it follows. However things didn’t go as planned :joy: :woozy_face: At this point, all of the images are spinning way too fast. I didn’t want to mess up with the frameRate(); of the sketch, because it also affects the movement speed of the peasy camera, so I thought it will be a good idea to use float time -= Sadly I didn’t make any difference. Any ideas on how to slow down the speed with the camera remaining unaffected?

import peasy.*;

PeasyCam cam;

PImage[] img;
int i = 0;

float time;

float num_img = 10; //number of images

float dist = 1400; // distance between  the images and the center

float angle = radians (360 / num_img); //// angle between the circles and the center 

float offset = radians (190); 

float amp = 0.02; //can be used to amplify the speed of the rotation

void setup() {
  size (1920, 1080, P3D);
  img = new PImage[5];


  cam = new PeasyCam(this, 500);
  cam.setMinimumDistance(500);
  cam.setMaximumDistance(5000);

  img[0] = loadImage("3.jpg");
  img[1] = loadImage("1.jpg");
  img[2] = loadImage("2.jpg");
  img[3] = loadImage("4.jpg");
  img[4] = loadImage("5.jpg");
}

void draw () {
 time -= 50.55;
  background (0);

  for (int i = 1; i <= num_img; i++) {

    float x = sin(angle *i + offset) * dist + width/2;
    float y = cos(angle *i + offset) * dist + height/2;


    imageMode(CENTER);
    img[int(random(1, 5))].resize(0, 800);
    image(img[int(random(1, 5))], x, y);
    
    
  }


  offset = offset + amp;
}
1 Like

Hi again! :wink:

This is exactly right, I forgot that the image() function doesn’t accept z coordinate argument!

You can refer to this previous thread to see how to display images properly in P3D :


For the second code, some improvements :

  • The part where you load your images :

    img[0] = loadImage("3.jpg");
    img[1] = loadImage("1.jpg");
    img[2] = loadImage("2.jpg");
    img[3] = loadImage("4.jpg");
    img[4] = loadImage("5.jpg");
    

    can be greatly improved by automating it. As you can see, there is a pattern that can be extracted : img[i] = loadImage("i.jpg") with i being 0, 1, 2, 3, 4…

    For this, check out a previous answer I gave about this :

    Effect not applying on a image in array - #2 by josephh

    (Side note, it’s better to name your array of images imgs rather than img because it can be confusing :wink: )

  • This is because the time variable is never used elsewhere other than the line where you subtract 50.55. Therefore it does nothing :yum:

    What drives the movement of the images is relies in this expression :

    sin(angle *i + offset)
    

    If you think about it, the trigonometric functions are oscillating with a period of TWO_PI (the time it takes to go from -1 to 1 and go back and if you go too fast, it’s oscillating very fast.

    Therefore the offset variable is increasing too much, you can try to reduce the amp variable.

example




// main image 
PImage[] img = new PImage[3];

int n=0, nAdd=5;

float angleMy; 

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

void setup() {
  size(1800, 800, P3D);

  img[0]=loadImage("page1.png"); 
  img[1]=loadImage("page2.jpg"); 
  img[2]=loadImage("page3.png");
  for (PImage img1 : img)
    img1.resize(320, 0);

  // set basics 
  textAlign(CENTER, CENTER); 
  ellipseMode(CENTER);
  imageMode(CENTER);
} // func 

void draw() {
  background(0);


  showImage3D(0, new PVector(170, 200, -320), 0.37); 
  showImage3D(1, new PVector(500, 600, -10), -0.4);
  showImage3D(2, new PVector(1300, 200, n+=nAdd), angleMy);

  if (n>120) 
    nAdd=-5; 

  if (n<-220) 
    nAdd=5; 

  angleMy+=0.0134;

  //
}//func draw()

void showImage3D(int i_, PVector pv, float angle) {
  pushMatrix();
  translate(pv.x, pv.y, pv.z);
  rotateY(angle); 
  image(img[ i_ ], 0, 0);
  popMatrix();
}
//

1 Like

Yes thanks @chrisir it’s true that you can use translate() with rotate() to position your image freely in 3D space :yum:

1 Like