3D camera rotation

Hello! im trying to create a 3D camera that rotates when mouse is dragged.
I created something that works, but the movement feels very strange.
Here’s my code:

Planet p = new Planet(new PVector(width / 2, height / 2, 100), 15);

PVector camPos = new PVector(width / 2, height / 2, 0);
PVector camDir = new PVector(width / 2, height / 2, 100);

float aYZ = 0;
float aXZ = 0;


void setup() {
  size(900, 900, P3D);

  perspective(PI / 2, float(width) / float(height), 0.1, 1000000);
}


void draw() {
  background(0);

  float camDirX = 100 * sin(aYZ) * cos(aXZ) + camPos.x;
  float camDirY = 100 * sin(aYZ) * sin(aXZ) + camPos.y;
  float camDirZ = 100 * cos(aYZ) + camPos.z;

  camDir = new PVector(camDirX, camDirY, camDirZ);


  println(sin(aYZ));

  camera(camPos.x, camPos.y, camPos.z, camDir.x, camDir.y, camDir.z, 0, 1, 0);

  if (keyPressed) {
    if (key == 'w') {
      camPos = camPos.add(camDir.copy().sub(camPos).normalize());
      camDir = camDir.add(camDir.copy().sub(camPos).normalize());
    } else if (key == 's') {
      camPos = camPos.add(camDir.copy().sub(camPos).normalize().mult(-1));
      camDir = camDir.add(camDir.copy().sub(camPos).normalize().mult(-1));
    }
  }


  p.show();
}


void mouseDragged() {
  float dx = mouseX - pmouseX;
  float dy = mouseY - pmouseY;

  aXZ += dy / 100;
  aYZ += dx / 100;
}

there is also a Planet and Body3D class:

class Body3D{
  PVector pos;
  PVector vel = new PVector(0,0,0);
  PVector acc = new PVector(0,0,0);
  
  float m;
  
  void applyAcc(PVector acc_){
    acc = acc.add(acc_);
  }
  
  void update(){
    vel = vel.add(acc);
    pos = pos.add(vel);
    
    acc = new PVector(0,0,0);
    
  }
}
class Planet extends Body3D{
  
  
  Planet(PVector pos_, float m_){
    this.pos = pos_;
    this.m = m_;
  }
  
  
  void show(){
    lights();
    noStroke();
    fill(255);
    translate(pos.x,pos.y,pos.z);
    sphere(this.m * 1.3);
  }
}

Thanks!

center in 3D is 0,0,0, NOT width/2 height/2

When your planet is in the center and you want to rotate the cam around it, the camDir stays fixed at 0,0,0; and camPos rotates around the planet

there is a nice trigonometry primer in the tutorials : https://www.processing.org/tutorials/


Edit: Example


Planet p = new Planet(new PVector(0, 0, 0), 15);
Planet p2 = new Planet(new PVector(110, 0, 110), 43);

PVector camPos = new PVector(0, 9, 0);
PVector camDir = new PVector(0, 0, 0);

void setup() {
  size(900, 900, P3D);
  perspective(PI / 2, float(width) / float(height), 0.1, 1000000);
}


void draw() {
  background(0);
  lights();

  float angle = map (mouseX, 
    0, width, 
    -PI, TWO_PI); 

  camPos = new PVector( 700 *  cos( angle ) + camDir.x, 
    map(mouseY, 0, height, -1333, 1333), 
    700 * sin( angle ) + camDir.z);

  camera( camPos.x, camPos.y, camPos.z, 
    camDir.x, camDir.y, camDir.z, 
    0, 1, 0);

  if (keyPressed) {
    if (key == 'w') {
      //    camPos = camPos.add(camDir.copy().sub(camPos).normalize());
      camDir = camDir.add(camDir.copy().sub(camPos).normalize());
    } else if (key == 's') {
      //  camPos = camPos.add(camDir.copy().sub(camPos).normalize().mult(-1));
      camDir = camDir.add(camDir.copy().sub(camPos).normalize().mult(-1));
    }
  }

  p.show();
  p2.show();

  camera();
  noLights();
  fill(255);
  textSize(19);
  textMode(SHAPE);
  text("height of cam is "+ str( map(mouseY, 0, height, -1333, 1333)), 
    -117, -117);
}

void mouseDragged() {
  //float dx = mouseX - pmouseX;
  //float dy = mouseY - pmouseY;

  //aXZ += dy / 100;
  //aYZ += dx / 100;
}
//---------------------------------------------------------------

class Planet extends Body3D {

  Planet(PVector pos_, float m_) {
    this.pos = pos_;
    this.m = m_;
  }

  void show() {
    lights();
    noStroke();
    fill(255);
    translate(pos.x, pos.y, pos.z);
    sphere(this.m * 1.3);
  }
}

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

class Body3D {
  PVector pos;
  PVector vel = new PVector(0, 0, 0);
  PVector acc = new PVector(0, 0, 0);

  float m;

  void applyAcc(PVector acc_) {
    acc = acc.add(acc_);
  }

  void update() {
    vel = vel.add(acc);
    pos = pos.add(vel);

    acc = new PVector(0, 0, 0);
  }
}
1 Like

thanks! But im trying to rotate the camera around its own axis and not around a object on the canvas. Like pressing the Left arrow will rotate the camera left, but with the mouse

I see.

My formula is correct just swap position and lookAt

yes. I know camDir must rotate, but i dont know how to translate mouse movement into this rotation.

It’s really just like in my code

map mouse to angle and use this angle

Coming from my code swap cam pos and
cam lookAt

I am sorry, I didn’t post my Sketch above.

I posted it now

cam is moving around center here

1 Like

Thx. This is great, but is it possible to have the y coordinate be a circle too? So you can keep looking up and then eventually come bak to where you were.

Right now the camDir has a maximum and minimum y coordinate, but in space there would not be a up or down, so the camera sould be able to rotate freely in every direction.

That’s true

I don’t know how to do this ad hoc

we have to ask one of the gurus

could you post your entire code to help them please?

I just addes some code for gravity wich also doesnt work… pls help

ArrayList<Planet> planets = new ArrayList<Planet>();

PVector camPos = new PVector(0, 0, 100);
PVector camDir = new PVector(0, 0, 0);

float aYZ = 0;
float aXZ;


float G = 0.01;


void setup() {
  size(900, 900, P3D);

  perspective(PI / 2, float(width) / float(height), 0.1, 1000000);

  aXZ = height / 2;

  planets.add(new Planet(new PVector(100, 0, 0), 5));
  planets.add(new Planet(new PVector(0, 100, 0), 5));
}


void draw() {
  background(0);

  if (aXZ > height) {
    aXZ = height;
  } else if (aXZ < 0) {
    aXZ = 0;
  }


  float angle = map (aYZ, 0, width, -PI, TWO_PI); 

  float camDirX = 700 * cos(angle) + camPos.x;
  float camDirY = map(aXZ, 0, height, -1333, 1333);
  float camDirZ = 700 * sin(angle) + camPos.z;

  camDir = new PVector(camDirX, camDirY, camDirZ);


  camera(camPos.x, camPos.y, camPos.z, camDir.x, camDir.y, camDir.z, 0, 1, 0);


  for (Planet p : planets) {
    p.show();
  }




  for (Planet b1 : planets) {
    for (Planet b2 : planets) {
      if (b1 != b2) {

        float r = dist(b1.pos.x, b1.pos.y, b1.pos.z, b2.pos.x, b2.pos.y, b2.pos.z);


        PVector p1 = new PVector(b2.pos.x, b2.pos.y, b2.pos.z);
        PVector p2 = new PVector(b1.pos.x, b1.pos.y, b1.pos.z);

        p1 = p1.sub(b1.pos);
        p2 = p2.sub(b2.pos);

        float a = G * ((b1.m * b2.m) / (r * r));

        b1.applyAcc(p1.mult(a).mult(1));
        b2.applyAcc(p2.mult(a).mult(1));
      }
    }
  }




  for (Planet p : planets) {
    p.update();
  }


  if (keyPressed) {
    if (key == 'w') {
      camPos = camPos.add(camDir.copy().sub(camPos).normalize());
      camDir = camDir.add(camDir.copy().sub(camPos).normalize());
    } else if (key == 's') {
      camPos = camPos.add(camDir.copy().sub(camPos).normalize().mult(-1));
      camDir = camDir.add(camDir.copy().sub(camPos).normalize().mult(-1));
    }
  }
}


void mouseDragged() {
  float dx = mouseX - pmouseX;
  float dy = mouseY - pmouseY;

  aXZ += dy / 1;
  aYZ += dx / 1;
}
class Body3D {
  PVector pos;
  PVector vel = new PVector(0, 0, 0);
  PVector acc = new PVector(0, 0, 0);

  float m;

  void applyAcc(PVector acc_) {
    acc = acc.add(acc_);
    
    strokeWeight(10);
    stroke(255);
    point(acc.x * 50 + pos.x,acc.y * 50 + pos.y,acc.z * 50 + pos.z);
  }

  void update() {
    vel = vel.add(acc.div(m));
    acc = new PVector(0, 0, 0);
    pos = pos.add(vel);
  }
}
class Planet extends Body3D{
  
  
  Planet(PVector pos_, float m_){
    this.pos = pos_;
    this.m = m_;
  }
  
  
  void show(){
    lights();
    noStroke();
    fill(255);
    translate(pos.x,pos.y,pos.z);
    sphereDetail(60);
    sphere(this.m * 1.3);
  }
}

This is a good resource for coding forces:
https://natureofcode.com/book/

:)

I have done this before in 2d, but after copy pasting the code into 3d it didnt work

cam rotates around itself now, but y still traditional



// cam rotates around ITSELF  
// Looking at center 

Planet p = new Planet(new PVector(0, 0, 0), 15);
Planet p2 = new Planet(new PVector(110, 0, -110), 13);
Planet p3 = new Planet(new PVector(210, 0, -110), 13);

final PVector camPos = new PVector(333, 9, 333);
PVector camDir = new PVector(0, 0, 0);

void setup() {
  size(900, 900, P3D);
  perspective(PI / 2, float(width) / float(height), 0.1, 1000000);
}


void draw() {
  background(0);
  lights();

  float angle = map (mouseX, 
    0, width, 
    -PI, TWO_PI); 

  camDir = new PVector( 1200 *  cos( angle ) + 0, 
    map(mouseY, 0, height, -1333, 1333), 
    1200 * sin( angle ) + 0);

  camera( camPos.x, camPos.y, camPos.z, 
    camDir.x, camDir.y, camDir.z, 
    0, 1, 0);

  if (keyPressed) {
    if (key == 'w') {
      //    camPos = camPos.add(camDir.copy().sub(camPos).normalize());
      camDir = camDir.add(camDir.copy().sub(camPos).normalize());
    } else if (key == 's') {
      //  camPos = camPos.add(camDir.copy().sub(camPos).normalize().mult(-1));
      camDir = camDir.add(camDir.copy().sub(camPos).normalize().mult(-1));
    }
  }

  p.show();
  p2.show();
  p3.show();

  // HUD 
  camera();
  noLights();
  fill(255);
  textSize(19);
  textMode(SHAPE);
  text("cam rotates around ITSELF. Height of cam is "+ str( map(mouseY, 0, height, -1333, 1333)), 
    -117, -117);
}

void mouseDragged() {
  //float dx = mouseX - pmouseX;
  //float dy = mouseY - pmouseY;

  //aXZ += dy / 100;
  //aYZ += dx / 100;
}
//---------------------------------------------------------------

class Planet extends Body3D {

  color col = color (random(255), 33, 333); 

  Planet(PVector pos_, float m_) {
    this.pos = pos_;
    this.m = m_;
  }

  void show() {
    lights();
    noStroke();
    fill(col);
    translate(pos.x, pos.y, pos.z);
    sphere(this.m);
  }
}

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

class Body3D {
  PVector pos;
  PVector vel = new PVector(0, 0, 0);
  PVector acc = new PVector(0, 0, 0);

  float m;

  void applyAcc(PVector acc_) {
    acc = acc.add(acc_);
  }

  void update() {
    vel = vel.add(acc);
    pos = pos.add(vel);

    acc = new PVector(0, 0, 0);
  }
}

Libraries

Please look at Peasycam