Making a 3D camera

Hello everyone,

I recently started coding a 3d program, some kind of game, but I remain stuck because of one simple thing : how to make a 3d camera ?

In fact, the program generates a cube, but I want it to move when I move my mouse as if it were real life or any game.

So here is what i’ve done so far :

float gx, gy, gz;
float rx, ry;
Cube cube1;
Cube cube2;

void setup(){
  cube1 = new Cube(0,0,0);
  cube2 = new Cube(-200,0,0);
  gx = 0;
  gy = 0;
  gz = 0;
  
  rx = 0;
  ry = 0;
  size(400, 400, P3D);
  frameRate(60);
}

void draw(){
  background(100);
  cube1.update();
  cube2.update();
  
  if (keyPressed == true) {
    if (key == 'R' || key == 'r') {
      gz = 0;
      gx = 0;
      gy = 0;
      rx = 0;
      ry = 0;
    } else if (key == 'Z' || key == 'z') {
      gz -= 1;
    } else if (key == 'S' || key == 's') {
      gz += 1;
    } else if (key == 'Q' || key == 'q') {
      gx -= 1;
    } else if (key == 'D' || key == 'd') {
      gx += 1;
    } else if (key == ' ') {
      gy -= 1;
    } else if (key == CODED && keyCode == CONTROL) {
      gy += 1;
    } else {
      gy += 0;
    }
  }
  
  if (mousePressed == true && mouseButton == RIGHT) {
    
    
    rx += (mouseX-pmouseX);
    ry -= (mouseY-pmouseY);
    if (ry > 50) {
      ry = 50;
    } else if (ry < -50) {
      ry = -50;
    }
    if (rx >= 200){
      rx = 0+(rx-200);
    } else if (rx <= -200){
      rx = 0-(rx+200);
    }
  }
  
  
  println("rx :" + rx);
  println("ry :" + ry);
}

class Cube{
  float x,y,z;
  
  Cube(float tempX, float tempY, float tempZ){
    x = tempX;
    y = tempY;
    z = tempZ;
  }
  
  void update(){
    pushMatrix();
    translate((width/2-gx),(height/2-gy),(-width/2-gz));
    rotateX(ry/32);
    rotateY(rx/32);
    stroke(0);
    strokeWeight(2);
    fill(255);
    beginShape();
    fill(255);
    vertex(x-100,y-100,z+100);
    vertex(x+100,y-100,z+100);
    vertex(x+100,y+100,z+100);
    vertex(x-100,y+100,z+100);
    endShape(CLOSE);
    
    beginShape();
    vertex(x-100,y-100,z+100);
    vertex(x-100,y-100,z-100);
    vertex(x-100,y+100,z-100);
    vertex(x-100,y+100,z+100);
    endShape(CLOSE);
    
    beginShape();
    vertex(x+100,y-100,z+100);
    vertex(x+100,y-100,z-100);
    vertex(x+100,y+100,z-100);
    vertex(x+100,y+100,z+100);
    endShape(CLOSE);
    
    beginShape();
    vertex(x-100,y-100,z-100);
    vertex(x+100,y-100,z-100);
    vertex(x+100,y+100,z-100);
    vertex(x-100,y+100,z-100);
    endShape(CLOSE);
    
    beginShape();
    vertex(x-100,y+100,z+100);
    vertex(x-100,y+100,z-100);
    vertex(x+100,y+100,z-100);
    vertex(x+100,y+100,z+100);
    endShape(CLOSE);
    
    beginShape();
    vertex(x-100,y-100,z+100);
    vertex(x-100,y-100,z-100);
    vertex(x+100,y-100,z-100);
    vertex(x+100,y-100,z+100);
    endShape(CLOSE);
    
    
    popMatrix();
  }
}

This code makes me able to generates two cubes and to navigate around theme, as they are always the center of my screen.

Now I want to do it differently, instead of having the camera move around the cube, I want the cube to move around the camera to simulate a first person camera. It goes well when it is about moving in a three dimensional space, but when I add rotation (with mouse movement), I just don’t know how to have the cube move as if it were like Minecraft, for those who know the game.

Here what i’ve done :

MOUSE MOVEMENT

  if (mousePressed == true && mouseButton == RIGHT) {
    
    
    rx += (mouseX-pmouseX);
    ry -= (mouseY-pmouseY);
    if (ry > 50) {
      ry = 50;
    } else if (ry < -50) {
      ry = -50;
    }
    if (rx >= 200){
      rx = 0+(rx-200);
    } else if (rx <= -200){
      rx = 0-(rx+200);
    }
  }

And my cube class is basically the same as the one specified in the first script, except i changed the translation :

translate(x-gx,y-gy+ry*4,z-gz);

But it doesn’t work well, and I can’t find how to do it.

Can anybody help me ?

2 Likes

Libraries

Okay, there are 2 libraries, Peasycam and QueasyCam

Command camera()

But you can also do manually what they do.

Look at the camera() command in the reference.

It comes with 9 parameters, but only the first 6 are interesting:

  • 3 for position of the camera (eye) and
  • 3 for lookAt (center)

https://www.processing.org/reference/camera_.html

Regards, Chrisir

3 Likes

a 3rd. option is still how you started,

and i could understand that,
even it might be not so comfortable like camera or a library
it has advantages, like you have full control over the code and function.
that is also the reason why i not retired my PTZ function, what actually is older
as today processing 3D view options.

you can take a look here

4 Likes

PTZ = pan tilt and zoom

1 Like

Thanks a lot ! Finally I used camera(), which seems to be simpler to use. But now I am facing another problem… I still want to make my 3d camera as if I were rotating my head. So I know I just have to change the lookAt positions.

But this is mainly a math problem, and I think I might have solved it using trigonometry, or at least I might have started solving it.

So for my Z-axis, I want the lookAt point to be exactly in front of my “eyes” when I move my mouse (well the camera moves with this point, so I want it to move on a sphere around my camera point so that I can look everywhere easily).

So I want to use cos(x) for my Z-axis, and I expect x to be equal to 0 when I’m looking straight ahead, so that the program returns 1 for cos(x). It works well. Now, when I look up or down, I want the lookAt point to move up or down, and of course to be perfectly parallel with my camera sticking point (on the z-axis).

Here is a simple drawing of what I want to do.


Horizontal axis : Z-Axis - Vertical axis : Y-Axis

The big red circle symbolizes the camera, the little black one symbolizes the initial lookAt point, and the green point symbolizes the lookAt point I want to get. As you can see, the green point is perfectly aligned with my camera, so I want its Z-position to be equal to cos(PI/2) which should be 0. Now, when I do it, it returns “-4.371139E-8” instead of 0, and I don’t know why. Cosinus with PI fractions seems to be not working.

Do you know a way to solve that problem ? Or do you know a simpler way to do what I want ?

Thank you very much

1 Like

I just tried to program this but I couldn’t upload it.

In 3D, normally the height above the surface is y, the left/right is x and the depth on the stage (in the room) is z. So the floor is in the x/z plane, walls go up y.

So you want

lookAtX = posX + cos(angle) * 10; 
lookAtY = 500;
lookAtZ = posY + sin(angle) * 10; 

angle = map (mouseX, 0, width, 0, 3*PI);

camera(posX,posY…
lookAtX,lookAtY…
0,1,0);

1 Like


// CONSTANT: the floor / field (y value)
final int GENERAL_Y_HEIGHT = 500-66; 

// Classes: The camera 
CameraClass cam; 

// The scene (background, field, boxes...) 
Scene scene = new Scene(); 

// minor tools 
Tools tools = new Tools(); 

// angle  
float angle; 

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

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

  // setup camera  
  cam = new CameraClass (  313, 
    GENERAL_Y_HEIGHT, 
    113 );

  // avoid clipping : 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 

void draw() {
  // set Canvas and Environment
  scene.setCanvasAndEnvironment(); 

  angle=map(mouseX, 0, width, 0, 3*PI);

  // camera 
  cam.setLookAt();   // 
  cam.set();    // apply the values of the class cam to the real camera

  // display the scene with the boxes and HUD text 
  scene.displayScene();
  //
} // func draw

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

void keyPressed() {
  switch(key) {
  case 'e':
    // 
    break;
  }
}

// =================================================================
// classes 

class Scene {

  // cubes 
  float angleCubes=45; // angle for the cubes in the scene

  void setCanvasAndEnvironment() {
    // set Canvas and Environment

    // clear canvas 
    background(111);

    // apply lights 
    lights();
  }

  void displayScene() {

    // Drawing of the scene / decoration  

    // Drawing of the red field  ---- 
    fill(255, 2, 2);//RED
    noStroke(); 
    tools.mySphere(500, GENERAL_Y_HEIGHT, 500, 20);
    tools.mySphere(100, GENERAL_Y_HEIGHT, 100, 20);
    tools.mySphere(100, GENERAL_Y_HEIGHT, 500, 20);
    tools.mySphere(500, GENERAL_Y_HEIGHT, 100, 20);

    // rect of lines  
    stroke(255, 2, 2);//RED
    // using 3D lines: 
    line(500, GENERAL_Y_HEIGHT, 500, 500, GENERAL_Y_HEIGHT, 100);  // up |
    line(500, GENERAL_Y_HEIGHT, 100, 100, GENERAL_Y_HEIGHT, 100);  // left <-
    line(100, GENERAL_Y_HEIGHT, 100, 100, GENERAL_Y_HEIGHT, 500 ); // down |
    line(100, GENERAL_Y_HEIGHT, 500, 500, GENERAL_Y_HEIGHT, 500 ); // right ->

    // one small wall of boxes
    stroke(0);
    int z = -60; 
    for (int x = 10; x < 600; x+= 100) {
      fill(x/3, 2, 2);
      for (int y = 410; y < 600; y+= 100) {
        tools.myBox(x, y, z, 24, angleCubes);
      }
    }

    // a few additional blue boxes
    fill(0, 0, 255);
    z=-400;
    tools.myBox(220, 10, z, 24, angleCubes);
    tools.myBox(600, 10, z, 24, angleCubes);
    z=-400;
    tools.myBox(220, 510, z, 24, angleCubes);
    tools.myBox(600, 510, z, 24, angleCubes);
    z=399;
    tools.myBox(220, 510, z, 24, angleCubes);
    tools.myBox(600, 510, z, 24, angleCubes);
    z=900;
    tools.myBox(220, 510, z, 24, angleCubes);
    tools.myBox(600, 510, z, 24, angleCubes);
    angleCubes++;
    //

    // text upper left corner (HUD)
    fill(0, 255, 0); 
    cam.HUD_text("Test " );  //
  }
  //
} // class 

// =================================================================

class CameraClass {

  // capsules the normal camera() command and its vectors 

  PVector camPos;     // its vectors 
  PVector camLookAt;
  PVector camUp;

  PVector camPosInitial;     // its vectors - the default (unchanged) 
  PVector camLookAtInitial;
  PVector camUpInitial; 

  float angleForCamerasUpAndDownMovement=0;   // angle for the slight up and down movement of the camera

  // constructor I - without parameters
  CameraClass() {
    // constr
    // set vectors 
    camPos    = new PVector(width/2.0, height/2.0, 990);
    camLookAt = new PVector(width/2.0, height/2.0, -600);
    camUp     = new PVector( 0, 1, 0 );
    // save the initial values
    camPosInitial    = camPos.copy();
    camLookAtInitial = camLookAt.copy();
    camUpInitial     = camUp.copy();
  }  // constr I

  // constructor II - with parameters for POS 
  CameraClass (float x1, float y1, float z1) {
    // constr
    // set vectors 
    camPos    = new PVector(x1, y1, z1);
    camLookAt = new PVector(width/2.0, height/2.0, -600);
    camUp     = new PVector( 0, 1, 0 );
    // save the initial values
    camPosInitial    = camPos.copy();
    camLookAtInitial = camLookAt.copy();
    camUpInitial     = camUp.copy();

    camPos = new PVector(x1, y1, z1);
  }  // constr II

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

  void set() {
    // apply internal class vectors to actual camera
    camera (camPos.x, camPos.y, camPos.z, 
      camLookAt.x, camLookAt.y, camLookAt.z, 
      camUp.x, camUp.y, camUp.z);
  }

  void setPos (float x1, float y1, float z1) {
    camPos = new PVector(x1, y1, z1);
  }

  void setLookAt () {
    // from angle
    float x1 = camPos.x+ cos(angle) *10 ; 
    float y1 = GENERAL_Y_HEIGHT; 
    float z1 = camPos.z + sin(angle) *10 ;
    camLookAt.set(x1, y1, z1);
  }

  void HUD_text (String a1) {
    // HUD text upper left corner - this must be called at the very end of draw()
    // this is a 2D HUD 
    camera();
    hint(DISABLE_DEPTH_TEST);
    noLights();
    // ------------------
    textSize(16);
    text (a1, 20, 20);
    // ------------------
    // reset all parameters to defaults
    textAlign(LEFT, BASELINE);
    rectMode(CORNER);
    textSize(32);
    hint(ENABLE_DEPTH_TEST); // no HUD anymore
    lights();
  } // method
  //
} // class

// ======================================

class Tools {
  // tools 

  void myBox(float x, float y, float z, 
    float size1, 
    float angleCube) {
    // one nice wrapper for build in box-command
    pushMatrix();
    translate(x, y, z);
    rotateY(radians(angleCube));
    rotateX(radians(45));
    box(size1);
    popMatrix();
  }

  void mySphere(float x, float y, float z, 
    float size1) {
    // one nice wrapper for build in sphere-command
    pushMatrix();
    translate(x, y, z);
    sphere(size1);
    popMatrix();
  }
}//class 
//
1 Like

and a version with wasd keys for moving the player (like in a first person shooter, FPS)

// CONSTANT: the floor / field (y value)
final int GENERAL_Y_HEIGHT = 500; 

// Classes: The camera 
CameraClass cam; 

// The scene (background, field, boxes...) 
Scene scene = new Scene(); 

// minor tools 
Tools tools = new Tools(); 

// angles  
float angleLeftRight; 
float angleUpDown=GENERAL_Y_HEIGHT-66;  // not a real angle!!! 

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

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

  // setup camera  
  cam = new CameraClass (313, 
    GENERAL_Y_HEIGHT - 66, 
    113);

  // avoid clipping : 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 

void draw() {
  // set Canvas and Environment
  scene.setCanvasAndEnvironment(); 

  angleLeftRight=map(mouseX, 0, width, 0, 3*PI);
  //  angleUpDown=map(mouseY, 0, height, GENERAL_Y_HEIGHT-150, GENERAL_Y_HEIGHT+150);// not a real angle!!! 
  if (pmouseY<mouseY-5)
    angleUpDown += .21; 
  else if (pmouseY>mouseY+5)
    angleUpDown += -.21; 

  // camera 
  cam.setLookAt();   // 
  cam.set();    // apply the values of the class cam to the real camera

  // display the scene with the boxes and HUD text 
  scene.displayScene();

  cam.keyPressed();
  //
} // func draw

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

void keyPressed() {
  //
  if (key=='r') {
    angleUpDown=GENERAL_Y_HEIGHT-66;  // not a real angle!!!
  }
}

// =================================================================
// classes 

class Scene {

  // cubes 
  float angleLeftRightCubes=45; // angleLeftRight for the cubes in the scene

  void setCanvasAndEnvironment() {
    // set Canvas and Environment

    // clear canvas 
    background(111);

    // apply lights 
    lights();
  }

  void displayScene() {

    // Drawing of the scene / decoration  

    // Drawing of the red field  ---- 
    fill(255, 2, 2);//RED
    noStroke(); 
    tools.mySphere(500, GENERAL_Y_HEIGHT, 500, 20);
    tools.mySphere(100, GENERAL_Y_HEIGHT, 100, 20);
    tools.mySphere(100, GENERAL_Y_HEIGHT, 500, 20);
    tools.mySphere(500, GENERAL_Y_HEIGHT, 100, 20);

    // rect of lines  
    stroke(255, 2, 2);//RED
    // using 3D lines: 
    line(500, GENERAL_Y_HEIGHT, 500, 500, GENERAL_Y_HEIGHT, 100);  // up |
    line(500, GENERAL_Y_HEIGHT, 100, 100, GENERAL_Y_HEIGHT, 100);  // left <-
    line(100, GENERAL_Y_HEIGHT, 100, 100, GENERAL_Y_HEIGHT, 500 ); // down |
    line(100, GENERAL_Y_HEIGHT, 500, 500, GENERAL_Y_HEIGHT, 500 ); // right ->

    // one small wall of boxes
    stroke(0);
    int z = -60; 
    for (int x = 10; x < 600; x+= 100) {
      fill(x/3, 2, 2);
      for (int y = 410; y < 600; y+= 100) {
        tools.myBox(x, y, z, 24, angleLeftRightCubes);
      }
    }

    // a few additional blue boxes
    fill(0, 0, 255);
    z=-400;
    tools.myBox(220, 10, z, 24, angleLeftRightCubes);
    tools.myBox(600, 10, z, 24, angleLeftRightCubes);
    z=-400;
    tools.myBox(220, 510, z, 24, angleLeftRightCubes);
    tools.myBox(600, 510, z, 24, angleLeftRightCubes);
    z=399;
    tools.myBox(220, 510, z, 24, angleLeftRightCubes);
    tools.myBox(600, 510, z, 24, angleLeftRightCubes);
    z=900;
    tools.myBox(220, 510, z, 24, angleLeftRightCubes);
    tools.myBox(600, 510, z, 24, angleLeftRightCubes);
    angleLeftRightCubes++;
    //

    // text upper left corner (HUD)
    fill(0, 255, 0); 
    cam.HUD_text("Test " );  //
  }
  //
} // class 

// =================================================================

class CameraClass {

  // capsules the normal camera() command and its vectors 

  PVector camPos;     // its vectors 
  PVector camLookAt;
  PVector camUp;

  PVector camPosInitial;     // its vectors - the default (unchanged) 
  PVector camLookAtInitial;
  PVector camUpInitial; 

  //  float angleLeftRightForCamerasUpAndDownMovement=0;   // angleLeftRight for the slight up and down movement of the camera

  // constructor I - without parameters
  CameraClass() {
    // constr
    // set vectors 
    camPos    = new PVector(width/2.0, height/2.0, 990);
    camLookAt = new PVector(width/2.0, height/2.0, -600);
    camUp     = new PVector( 0, 1, 0 );
    // save the initial values
    camPosInitial    = camPos.copy();
    camLookAtInitial = camLookAt.copy();
    camUpInitial     = camUp.copy();
  }  // constr I

  // constructor II - with parameters for POS 
  CameraClass (float x1, float y1, float z1) {
    // constr
    // set vectors 
    camPos    = new PVector(x1, y1, z1);
    camLookAt = new PVector(width/2.0, height/2.0, -600);
    camUp     = new PVector( 0, 1, 0 );
    // save the initial values
    camPosInitial    = camPos.copy();
    camLookAtInitial = camLookAt.copy();
    camUpInitial     = camUp.copy();

    camPos = new PVector(x1, y1, z1);
  }  // constr II

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

  void set() {
    // apply internal class vectors to actual camera
    camera (camPos.x, camPos.y, camPos.z, 
      camLookAt.x, camLookAt.y, camLookAt.z, 
      camUp.x, camUp.y, camUp.z);
  }

  void setPos (float x1, float y1, float z1) {
    camPos = new PVector(x1, y1, z1);
  }

  void setLookAt () {
    // from angleLeftRight
    float x1 = camPos.x + cos(angleLeftRight) *10; 
    float y1 = angleUpDown;   // GENERAL_Y_HEIGHT; 
    float z1 = camPos.z + sin(angleLeftRight) *10;
    camLookAt.set(x1, y1, z1);
  }

  void keyPressed() {
    if (!keyPressed) 
      return;

    switch(key) {

    case 'w':
      // run forward / running towards lookat 
      float x1 = camPos.x + cos(angleLeftRight) *1; 
      float z1 = camPos.z + sin(angleLeftRight) *1;
      camPos.set(x1, camPos.y, z1);
      break;

    case 's':
      // run backward 
      x1 = camPos.x - cos(angleLeftRight) *1; 
      z1 = camPos.z - sin(angleLeftRight) *1;
      camPos.set(x1, camPos.y, z1);
      break;

    case 'a': 
      // left / sideways 
      x1 = camPos.x + cos(angleLeftRight-HALF_PI) * 1;
      z1 = camPos.z + sin(angleLeftRight-HALF_PI) * 1;
      camPos.set(x1, camPos.y, z1);
      break;

    case 'd':
      // right 
      x1 = camPos.x - cos(angleLeftRight-HALF_PI) * 1;
      z1 = camPos.z - sin(angleLeftRight-HALF_PI) * 1;
      camPos.set(x1, camPos.y, z1);
      break;
    }//switch
  }// method

  void HUD_text (String text_) {
    // HUD text upper left corner - this must be called at the very end of draw()
    // this is a 2D HUD 
    camera();
    hint(DISABLE_DEPTH_TEST);
    noLights();
    // ------------------
    textSize(16);
    text (text_, 20, 20);
    // ------------------
    // reset all parameters to defaults
    textAlign(LEFT, BASELINE);
    rectMode(CORNER);
    textSize(32);
    hint(ENABLE_DEPTH_TEST); // no HUD anymore
    lights();
  } // method
  //
} // class

// ======================================

class Tools {
  // tools 

  void myBox(float x, float y, float z, 
    float size1, 
    float angleLeftRightCube) {
    // one nice wrapper for build in box-command
    pushMatrix();
    translate(x, y, z);
    rotateY(radians(angleLeftRightCube));
    rotateX(radians(45));
    box(size1);
    popMatrix();
  }

  void mySphere(float x, float y, float z, 
    float size1) {
    // one nice wrapper for build in sphere-command
    pushMatrix();
    translate(x, y, z);
    sphere(size1);
    popMatrix();
  }
}//class 
//
2 Likes

Thank you so much :grinning:. It will take some time to try to understand everything you wrote but it works perfectly.
One very last question, do you know how to lock the mouse inside the window ?

So that you can move your camera without having the mouse come out of the window and stopping the movement. I’ve seen some people using the Robot class, but I didn’t find anything well-working.

I think that the robot class is the way to go

1 Like

Will use it ! Thank you for everything :wink:

in this new version you can either

  • look around (FPS) with mouse and “wasd” keys OR
  • let the camera fly around a spot in front of you (denoted by a green sphere)

Toggle with r

Chrisir

// CONSTANT: the floor / field (y value)
final int GENERAL_Y_HEIGHT = 500; 

// rotate around itself (player, FPS) OR around a point 
boolean modeCamRotatesAroundPoint = false; 

// Classes: The camera 
CameraClass cam; 

// The scene (background, field, boxes...) 
Scene scene = new Scene(); 

// minor tools 
Tools tools = new Tools(); 

// angles  
float angleLeftRight; 
float angleUpDown=GENERAL_Y_HEIGHT-66;  // not a real angle!!! 

float modeCamRotatesAroundPointAngle; 
PVector spherePosPV=new PVector(0, GENERAL_Y_HEIGHT-500, 0);
float prevAngle; 

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

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

  // setup camera  
  cam = new CameraClass (313, 
    GENERAL_Y_HEIGHT - 66, 
    113);

  // avoid clipping : 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 

void draw() {
  // set Canvas and Environment
  scene.setCanvasAndEnvironment(); 

  if (modeCamRotatesAroundPoint) {
    // show Cam Rotates Around Point
    showModeCamRotatesAroundPoint();
  } else {
    // first person shooter perspective (FPS)
    showFPS();
  }//else 

  // display the scene with the boxes and HUD text 
  scene.displayScene();
  //
} // func draw

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

void showModeCamRotatesAroundPoint() {
  // rotate around a point 
  cam.setPosAngle(modeCamRotatesAroundPointAngle); 
  cam.set();    // apply the values of the class cam to the real camera

  tools.mySphere(spherePosPV.x, spherePosPV.y, spherePosPV.z, 
    7);

  if (spherePosPV.y >= GENERAL_Y_HEIGHT) { 
    spherePosPV.y=GENERAL_Y_HEIGHT;  
    modeCamRotatesAroundPointAngle+=.032;
  } else {
    // sphere falls 
    spherePosPV.y+=10;
  }//
}

void showFPS() {
  // rotate around itself (player, FPS)
  angleLeftRight=map(mouseX, 0, width, 0, 3*PI);
  //  angleUpDown=map(mouseY, 0, height, GENERAL_Y_HEIGHT-150, GENERAL_Y_HEIGHT+150);// not a real angle!!! 
  if (pmouseY<mouseY-5)
    angleUpDown += .21; 
  else if (pmouseY>mouseY+5)
    angleUpDown += -.21; 

  // camera 
  cam.setLookAtAngle(angleLeftRight);   // 
  cam.set();    // apply the values of the class cam to the real camera

  // sphere disappears 
  if (spherePosPV.y < GENERAL_Y_HEIGHT-310) { 
    // do nothing
  } else {
    // sphere 
    spherePosPV.y-=10;
    tools.mySphere(spherePosPV.x, spherePosPV.y, spherePosPV.z, 
      7);
  }//else 
  cam.keyPressedThroughout();
}//func 

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

void keyPressed() {

  //
  if (key=='r') {
    // Toggle: FPS OR cam rotates AROUND a point  
    modeCamRotatesAroundPoint = 
      ! modeCamRotatesAroundPoint;  // toggle 

    // modeCamRotatesAroundPoint has a new value now, 
    // it's a new mode so we can set some start conditions for the new mode.  
    if (modeCamRotatesAroundPoint) {
      // starting mode: modeCamRotatesAroundPoint

      prevAngle=angleLeftRight; 
      modeCamRotatesAroundPointAngle=angleLeftRight-PI; 
      // define camera 
      float x1 = cam.camPos.x + cos(angleLeftRight) *300; 
      float y1 = angleUpDown;   // GENERAL_Y_HEIGHT; 
      float z1 = cam.camPos.z + sin(angleLeftRight) *300;
      cam.setLookAt(x1, y1, z1);
      // define sphere 
      spherePosPV=cam.camLookAt.copy();
      spherePosPV.y=GENERAL_Y_HEIGHT-310;
    } else {
      // starting mode PVS
      angleLeftRight=modeCamRotatesAroundPointAngle;
      float x1 = cam.camLookAt.x - cos(prevAngle) *300; 
      float y1 = angleUpDown;   // GENERAL_Y_HEIGHT; 
      float z1 = cam.camLookAt.z - sin(prevAngle) *300;
      cam.camPos.set(x1, y1, z1); // =cam.camLookAt.copy();
    }
    //
  } else if (key==ESC) {
    modeCamRotatesAroundPoint = false;
    key=0; // kill ESC
  }// else if
}//func 

// =================================================================
// classes 

class Scene {

  // cubes 
  float angleLeftRightCubes=45; // angleLeftRight for the cubes in the scene

  void setCanvasAndEnvironment() {
    // set Canvas and Environment

    // clear canvas 
    background(111);

    // apply lights 
    lights();
  }

  void displayScene() {

    // Drawing of the scene / decoration  

    // Drawing of the red field  ---- 
    fill(255, 2, 2);//RED
    noStroke(); 
    tools.mySphere(500, GENERAL_Y_HEIGHT, 500, 20);
    tools.mySphere(100, GENERAL_Y_HEIGHT, 100, 20);
    tools.mySphere(100, GENERAL_Y_HEIGHT, 500, 20);
    tools.mySphere(500, GENERAL_Y_HEIGHT, 100, 20);

    // rect of lines  / floor / field 
    stroke(255, 2, 2);//RED
    // using 3D lines: 
    line(500, GENERAL_Y_HEIGHT, 500, 500, GENERAL_Y_HEIGHT, 100);  // up |
    line(500, GENERAL_Y_HEIGHT, 100, 100, GENERAL_Y_HEIGHT, 100);  // left <-
    line(100, GENERAL_Y_HEIGHT, 100, 100, GENERAL_Y_HEIGHT, 500 ); // down |
    line(100, GENERAL_Y_HEIGHT, 500, 500, GENERAL_Y_HEIGHT, 500 ); // right ->

    // one small wall of boxes
    stroke(0);
    int z = -60; 
    for (int x = 10; x < 600; x+= 100) {
      fill(map(x, 10, 600, 111, 255), 2, 2);
      for (int y = 410; y < 600; y+= 100) {
        tools.myBox(x, y, z, 24, angleLeftRightCubes);
      }
    }

    // a few additional blue boxes
    fill(0, 0, 255);
    z=-400;
    tools.myBox(220, 10, z, 24, angleLeftRightCubes);
    tools.myBox(600, 10, z, 24, angleLeftRightCubes);
    z=-400;
    tools.myBox(220, 510, z, 24, angleLeftRightCubes);
    tools.myBox(600, 510, z, 24, angleLeftRightCubes);
    z=399;
    tools.myBox(220, 510, z, 24, angleLeftRightCubes);
    tools.myBox(600, 510, z, 24, angleLeftRightCubes);
    z=900;
    tools.myBox(220, 510, z, 24, angleLeftRightCubes);
    tools.myBox(600, 510, z, 24, angleLeftRightCubes);
    angleLeftRightCubes++;
    //

    // text upper left corner (HUD)
    fill(0, 255, 0); 
    cam.HUD_text("Use Mouse. Click r to toggle mode. " );  //
  }
  //
} // class 

// =================================================================

class CameraClass {

  // capsules the normal camera() command and its vectors 

  PVector camPos;     // its vectors 
  PVector camLookAt;
  PVector camUp;

  PVector camPosInitial;     // its vectors - the default (unchanged) 
  PVector camLookAtInitial;
  PVector camUpInitial; 

  //  float angleLeftRightForCamerasUpAndDownMovement=0;   // angleLeftRight for the slight up and down movement of the camera

  // constructor I - without parameters
  CameraClass() {
    // constr
    // set vectors 
    camPos    = new PVector(width/2.0, height/2.0, 990);
    camLookAt = new PVector(width/2.0, height/2.0, -600);
    camUp     = new PVector( 0, 1, 0 );
    // save the initial values
    camPosInitial    = camPos.copy();
    camLookAtInitial = camLookAt.copy();
    camUpInitial     = camUp.copy();
  }  // constr I

  // constructor II - with parameters for POS 
  CameraClass (float x1, float y1, float z1) {
    // constr
    // set vectors 
    camPos    = new PVector(x1, y1, z1);
    camLookAt = new PVector(width/2.0, height/2.0, -600);
    camUp     = new PVector( 0, 1, 0 );
    // save the initial values
    camPosInitial    = camPos.copy();
    camLookAtInitial = camLookAt.copy();
    camUpInitial     = camUp.copy();

    camPos = new PVector(x1, y1, z1);
  }  // constr II

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

  void set() {
    // apply internal class vectors to actual camera
    camera (camPos.x, camPos.y, camPos.z, 
      camLookAt.x, camLookAt.y, camLookAt.z, 
      camUp.x, camUp.y, camUp.z);
  }

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

  void setPos (float x1, float y1, float z1) {
    camPos.set(x1, y1, z1);
  }

  void setLookAt (float x1, float y1, float z1) {
    camLookAt.set(x1, y1, z1);
  }

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

  void setPosAngle (float angle_) {
    // look to point while rotating around it 
    // 
    float x1 = camLookAt.x + cos(angle_) *300; 
    float y1 = angleUpDown;   // GENERAL_Y_HEIGHT; 
    float z1 = camLookAt.z + sin(angle_) *300;
    camPos.set(x1, y1, z1);
  }

  void setLookAtAngle (float angleLeftRight) {
    // FPS 
    // from angleLeftRight
    float x1 = camPos.x + cos(angleLeftRight) *10; 
    float y1 = angleUpDown;   // GENERAL_Y_HEIGHT; 
    float z1 = camPos.z + sin(angleLeftRight) *10;
    camLookAt.set(x1, y1, z1);
  }

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

  void keyPressedThroughout() {

    if (!keyPressed) 
      return;

    switch(key) {

    case 'w':
      // run forward / running towards lookat 
      float x1 = camPos.x + cos(angleLeftRight) *1; 
      float z1 = camPos.z + sin(angleLeftRight) *1;
      camPos.set(x1, camPos.y, z1);
      break;

    case 's':
      // run backward 
      x1 = camPos.x - cos(angleLeftRight) *1; 
      z1 = camPos.z - sin(angleLeftRight) *1;
      camPos.set(x1, camPos.y, z1);
      break;

    case 'a': 
      // left / sideways 
      x1 = camPos.x + cos(angleLeftRight-HALF_PI) * 1;
      z1 = camPos.z + sin(angleLeftRight-HALF_PI) * 1;
      camPos.set(x1, camPos.y, z1);
      break;

    case 'd':
      // right 
      x1 = camPos.x - cos(angleLeftRight-HALF_PI) * 1;
      z1 = camPos.z - sin(angleLeftRight-HALF_PI) * 1;
      camPos.set(x1, camPos.y, z1);
      break;
    }//switch
  }// method

  void HUD_text (String text_) {
    // HUD text upper left corner - this must be called at the very end of draw()
    // this is a 2D HUD 
    camera();
    hint(DISABLE_DEPTH_TEST);
    noLights();
    // ------------------
    textSize(16);
    text (text_, 20, 20);
    // ------------------
    // reset all parameters to defaults
    textAlign(LEFT, BASELINE);
    rectMode(CORNER);
    textSize(32);
    hint(ENABLE_DEPTH_TEST); // no HUD anymore
    lights();
  } // method
  //
} // class

// ======================================

class Tools {
  // tools 

  void myBox(float x, float y, float z, 
    float size1, 
    float angleLeftRightCube) {
    // one nice wrapper for build in box-command
    pushMatrix();
    translate(x, y, z);
    rotateY(radians(angleLeftRightCube));
    rotateX(radians(45));
    box(size1);
    popMatrix();
  }

  void mySphere(float x, float y, float z, 
    float size1) {
    // one nice wrapper for build in sphere-command
    pushMatrix();
    noStroke(); 
    translate(x, y, z);
    sphere(size1);
    popMatrix();
  }
}//class 
//
2 Likes