First-person camera (3D)

My first-person camera code is having the following problems: changing the [starting] position of the camera makes the reference sphere disappear, replaced by a white screen; when playing around with the commented-out “box crosshair” code at the bottom, I discovered the point I’m looking at is getting closer and farther from me based on where I’m looking up or down, instead of a perfect sphere of distance as it should be, and the push and pop matrix code at the bottom just completely breaks everything if both are running:

PVector pos = new PVector(w/2, h/2, 50);
PVector lookDir = new PVector(0, pos.z);

void setup() {
  background(240);
}

void settings(){
  size(w, h, P3D);
}

void look(){
  if(keyPressed){
    if(key == CODED){
      if(keyCode == RIGHT){
        if (lookDir.x == 359){
          lookDir.x = 0;
        }
        else{
          lookDir.x += 1;
        }
        println("right");
      }
      if(keyCode == LEFT){
        if (lookDir.x == 0){
          lookDir.x = 359;
        }
        else{
          lookDir.x -= 1;
        }
        println("left");
      }
      if(keyCode == UP){
        if (lookDir.y == 89){
          lookDir.y = 89;
        }
        else{
          lookDir.y += 1;
        }
        print(lookDir.y);
        println("up");
    }
    if(keyCode == DOWN){
        if (lookDir.y == -269){
          lookDir.y = -269;
        }
        else{
          lookDir.y -= 1;
        }
        print(lookDir.y);
        println("down");
      }
    }
  }
}

void draw() {
  background(240);
  pushMatrix();
  translate(width/2, height/2);
  stroke(20);
  sphere(200);
  popMatrix();
  look();
  perspective(PI/3.0, width/height, pos.z, pos.z*10);
  //pushMatrix();
  camera(pos.x, pos.y, pos.z, pos.x+cos(radians(lookDir.x))*(10-sin(radians(lookDir.y))*10), pos.y+sin(radians(lookDir.x))*(10-sin(radians(lookDir.y))*10), pos.z+cos(radians(lookDir.y))*10, 0, 0, -1);
  //translate(pos.x+cos(radians(lookDir.x))*(10-sin(radians(lookDir.y))*10), pos.y+sin(radians(lookDir.x))*(10-sin(radians(lookDir.y))*10), pos.z+cos(radians(lookDir.y))*10);
  //box(3);
  //popMatrix();
}

If anyone can help me with any of this, that would be amazing. Thanks!

1 Like

USE w and s and mouse

you run where you look (so steer with the mouse)



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

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

int w = 1200;
int h = 900;

PVector pos = new PVector(300, GENERAL_Y_HEIGHT, 250);

float lookAngleLeftAndRight, // angle 
   lookAngleUpAndDown;   // not an angle 

void setup() {
  background(240);
  // noCursor();
  mouseX=width/10*12;
}

void settings() {
  size(w, h, P3D);
}

void draw() {
  background(240);
  avoidClipping();
  lights();

  lookAngleLeftAndRight = map(mouseX,
    0, width,
    -470, 580);

  lookAngleUpAndDown = map(mouseY,
    0, height,
    GENERAL_Y_HEIGHT - 22 - 13, GENERAL_Y_HEIGHT -22 + 13 );

  camera(pos.x, GENERAL_Y_HEIGHT-22, pos.z,
    pos.x+cos(radians(lookAngleLeftAndRight))*3, lookAngleUpAndDown, pos.z+sin(radians(lookAngleLeftAndRight))*3,
    0, 1, 0);

  scene();

  readkeysThroughout();

  // Init 2D part:  ------------------------------------------------------------------
  hint(DISABLE_DEPTH_TEST);
  camera();
  noLights();
  // 2D part:
  stroke(0);
  line(width/2, height/2-22,
    width/2, height/2+22);
  line(width/2-22, height/2,
    width/2+22, height/2);
  hint(ENABLE_DEPTH_TEST); // reset to 3D
}

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

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

  if (key != CODED) {
    switch(key) {
    case 'w':
      pos.x+=cos(radians(lookAngleLeftAndRight))*3;
      pos.z+=sin(radians(lookAngleLeftAndRight))*3;
      break;
    case 's':
      pos.x-=cos(radians(lookAngleLeftAndRight))*3;
      pos.z-=sin(radians(lookAngleLeftAndRight))*3;
      break;
    case'a':
      // to do
      break;
    case'd':
      // to do
      break;
    }//switch
    //
    return; // leave
  }//if

  // from now on all is coded ---------------------

  if (keyCode == RIGHT) {
    println("right");
  } else if (keyCode == LEFT) {
    println("left");
  } else if (keyCode == UP) {
    println("up");
  } else if (keyCode == DOWN) {
    println("down");
  }
}

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

void scene() {

  // scene
  // 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) {
      myBox(x, y, z, 24, angleLeftRightCubes);
    }
  }

  pushMatrix();
  translate(width/2, GENERAL_Y_HEIGHT-22, height/2);
  //stroke(20);
  noStroke();
  fill( 0, 222, 0); // green
  sphere(22);
  popMatrix();

  pushMatrix();
  translate(0, GENERAL_Y_HEIGHT-22, 0);
  //stroke(20);
  noStroke();
  fill( 0, 0, 222); // blue
  sphere(22);
  popMatrix();

  pushMatrix();
  translate(width/2, GENERAL_Y_HEIGHT-22, 0);
  //stroke(20);
  noStroke();
  fill( 222, 0, 0); // red
  sphere(22);
  popMatrix();
}

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 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
//

1 Like

Remarks 1

  • Check out library QuasyCam
  • Problem that the mouse gets over the screen border left or right: There is a Robot class to handle this. I dunno.

Remarks 2

I removed perspective() command

I used the default camera orientation 0, 1, 0 from camera() / Reference / Processing.org

Probably you’ve been inside the sphere. Sphere too big.

1 Like

You are not using perspective() quite correctly. The 3rd and 4th parameters are the near and far clipping distances which are relative to the camera. If you had them set to say, 1 and 10 then you would only see geometry that is between 1 and 10 units away in front of whatever direction the camera is facing – anything closer or further away is cut off.

In your case, setting the near clipping distance to the camera z position means that anything between you and the origin is cut off which is likely not what you want. If your camera is 50 away from the origin, then try setting the near distance to 1 and the far to 500.

In theory, we would like the near and far distances to be 0 and infinity, but the graphics hardware has to map the pixels of the triangles that are drawn with depth values that are between the near and far to integer values stored in the depth buffer. If you give too big of a near-far range, the integer mapping loses precision and triangles at different distances start flickering through each other which is called z-fighting. It’s usually safe to make the far distance pretty big, but try to avoid making the near too small. Just be sure the near is small enough that it stays less than the distance from your camera to the nearest objects as you move around.

2 Likes