First person camera problem

Hi guys, i'm trying to implement a first person camera for a little program i'm writing. I actually did implement the camera (it works with differentials and spherical coordinates) and it's doing quite well except for a problem. As i look around the scene (move my mouse), the cursor will eventually fall off the screen and of course stop working. How can i fix that? Here is my code:

void updateCamera(){

    this.horizontalAngle += (mouseX - pmouseX)/100f;
    this.verticalAngle -= (mouseY - pmouseY)/100f;

    if(this.verticalAngle < -PI+0.1)
      this.verticalAngle = -PI+0.1;
    if(this.verticalAngle > 0)
      this.verticalAngle = 0;

    centerX = this.pos.x + cos(horizontalAngle) * sin(verticalAngle);
    centerY = this.pos.y + sin(horizontalAngle) * sin(verticalAngle);
    centerZ = this.pos.z + cos(verticalAngle);

    camera(this.pos.x, this.pos.y, this.pos.z, this.centerX, this.centerY, this.centerZ, 0, 0, -1);

}

I tried the robot class with robot.mouseMove(); to set the mouse to center every time i move it, but in this way my camera gets locked. Suggestions? Thank you!

Tagged:

Answers

  • Answer ✓

    THere is a library for that QueasyCam

  • Thank you, i knew there were some libraries but i like to write code by myself, it makes me understand code a lot better (I'm not a programmer, i do this in my free time).

    Is there any other way to fix this problem?

  • As i look around the scene (move my mouse), the cursor will eventually fall off the screen and of course stop working.

    Without having an MCVE that allows us to test the behavior you are describing it is hard to tell why it might be happening or give you specific advice.

    I'm also not sure what you mean by your camera getting locked. Are you referring to gimbol lock?

    Even if you do not want to use QuesyCam, you might still be interested in browsing its source code, which can give you some ideas about the way it approaches these problems.

  • edited March 2018

    Here is my problem: http://gph.is/2oU8ifq

    I hope this is allowed by the forum, i didn't really know how to show you guys what was happening so i created this gif. It's small and low quality but you can see what's going on with the mouse. For clarity, i'll post the entire code for the player class. I commented it so you can better understand what i did:

    class Player{
    
      PVector pos, facing, normLR, normFB;
    
      float horizontalAngle, verticalAngle;
      float centerX, centerY, centerZ;
    
      Player(){
        pos = new PVector();     //Player position
        facing = new PVector();  //Facing direction
        normLR = new PVector();  //Local x axis (Left and Right movement)
        normFB = new PVector();  //Local y axis (Forward and Backwards movement)
    
        this.pos.x = 10;         //Starting position
        this.pos.y = 10;
        this.pos.z = 30;
    
        centerX = 0;             //Starting facing
        centerY = 0;
        centerZ = 0;
      }
    
      void updateCamera(){       //This function is called in draw method
    
        if(left)                 //Reference to booleans in the main class, for movement.
          this.pos.sub(normLR);
        if(right)
          this.pos.add(normLR);
        if(forward)
          this.pos.sub(normFB);
        if(backwards)
          this.pos.add(normFB);
        if(down)
          this.pos.z -= 0.5;
        if(up)
          this.pos.z += 0.5;
    
        // Here i update facing angles...
        this.horizontalAngle += (mouseX - pmouseX) * 0.01;
        this.verticalAngle -= (mouseY - pmouseY) * 0.01;
    
        if(this.verticalAngle < -PI+0.1)
          this.verticalAngle = -PI+0.1;
        if(this.verticalAngle > 0)
          this.verticalAngle = 0;
    
        //... and calculate the direction where the player should be facing
        centerX = this.pos.x*blockSize + 100 * cos(horizontalAngle) * sin(verticalAngle);
        centerY = this.pos.y*blockSize + 100 * sin(horizontalAngle) * sin(verticalAngle);
        centerZ = this.pos.z*blockSize + 100 * cos(verticalAngle);
    
        facing.set(this.centerX - this.pos.x*blockSize, this.centerY - this.pos.y*blockSize, this.centerZ - this.pos.z*blockSize);
        facing.normalize();
    
        //Then i calculate local x and y axis, so the player will always move in the local l, r, forw and backw directions
        normLR.set(1, -facing.x/facing.y, 0);
        if(facing.y > 0)
          normLR.mult(-1);
        normLR.normalize();
        normLR.div(2);
    
        normFB.set(1, -normLR.x/normLR.y, 0);
        if(normLR.y > 0)
          normFB.mult(-1);
        normFB.normalize();
        normFB.div(2);
    
        //Update camera
        camera(this.pos.x*blockSize, this.pos.y*blockSize, this.pos.z*blockSize, this.centerX, this.centerY, this.centerZ, 0, 0, -1);
    
      }
    
    }
    
  • edited March 2018

    Ah, I understand now -- you wanted the mouse drag to be sending events with its location even when the mouse pointer travels outside the bounds of the window.

    Were you able to resolve this issue?

  • edited March 2018

    I actually did! It took me a while but i made a simple camera class, easy to implement. In the end i just had to use the Robot class method mouseMove and play with the pmouseX and pmouseY variables. I'm kinda proud of it hahaha

    If you want to give it a try, here is the code. If you want to test it on any P3D sketch, you have to set the main tab like this:

        Camera camera;
    
        void setup() {
          size(width, height, P3D);
    
          camera = new Camera(startingX, startingY, startingZ);
          camera.setVelocity(0.5); //If not called, is set to 0.2 as default
        }
    
        void draw() {
          background(someColor);
    
          //RENDER SOMETHING HERE
    
          camera.update();
        }
    
        void keyPressed() {
          camera.keyPressed();
        }
    
        void keyReleased() {
          camera.keyReleased();
        }
    

    Here is the Camera class. You move with WASD, SPACEBAR and SHIFT. Mouse movement is not really smooth, but works fine. There you go:

    import java.awt.Robot;
    
    class Camera{
    
      public PVector pos;
    
      private Robot robot;
      private PVector vel, acc, normLR, normFB, facing;
      private float horizontalAngle, verticalAngle;
      private float centerX, centerY, centerZ;
      private boolean left, right, forward, backwards, up, down;
    
      private float velocity = 0.2;
      private float fluidity = 0.9;
    
      Camera(int x, int y, int z){
        this.pos = new PVector();     //Camera position
        this.vel = new PVector();     //Camera velocity
        this.acc = new PVector();     //Camera acceleration
    
        this.facing = new PVector();  //Facing direction
        this.normLR = new PVector();  //Local x axis (Left and Right movement)
        this.normFB = new PVector();  //Local y axis (Forward and Backwards movement)
    
        this.pos.x = x; //Starting position given by arguments
        this.pos.y = y;
        this.pos.z = z;
    
        try{
          this.robot = new Robot();
        }catch(Exception e){}
    
        perspective(PI/3.0, (float) width/height, 0.001, 10000);
        noCursor();
      }
    
      public void update(){
    
        //CAMERA MOTION IN 3D SPACE
        if(left)
          this.acc.sub(normLR);
        if(right)
          this.acc.add(normLR);
        if(forward)
          this.acc.sub(normFB);
        if(backwards)
          this.acc.add(normFB);
        if(down)
          this.acc.z -= 1;
        if(up)
          this.acc.z += 1;
    
        if(up == false && down == false && left == false && right == false && forward == false && backwards == false){
          this.acc.mult(fluidity * 0.1);
          this.vel.mult(fluidity); 
        }
    
        this.acc.limit(velocity * 0.1);
        this.vel.add(acc);
        this.vel.limit(velocity);
        this.pos.add(this.vel);
    
        //CAMERA FACING
        this.robot.mouseMove((int)getWindowLocation().x + width/2, (int)getWindowLocation().y + height/2);
        pmouseX = width/2;
        pmouseY = height/2;
    
        this.horizontalAngle += (mouseX - pmouseX) * 0.01;
        this.verticalAngle += (mouseY - pmouseY) * 0.01;
    
        if(this.verticalAngle < -PI + 0.1)
          this.verticalAngle = -PI + 0.1;
        if(this.verticalAngle > -0.1)
          this.verticalAngle = -0.1;
    
        this.centerX = this.pos.x + cos(horizontalAngle) * sin(verticalAngle);
        this.centerY = this.pos.y + sin(horizontalAngle) * sin(verticalAngle);
        this.centerZ = this.pos.z - cos(verticalAngle);
    
        this.facing.set(this.centerX - this.pos.x, this.centerY - this.pos.y, this.centerZ - this.pos.z);
        this.facing.normalize();
    
        //CALCULATE LOCAL X & Y AXES
        this.normLR.set(1, -this.facing.x/(this.facing.y + 0.0001), 0);
        if(this.facing.y > 0)
          this.normLR.mult(-1);
        this.normLR.normalize();
    
        this.normFB.set(1, -this.normLR.x/(this.normLR.y + 0.0001), 0);
        if(this.normLR.y > 0)
          this.normFB.mult(-1);
        this.normFB.normalize();
    
        camera(this.pos.x, this.pos.y, this.pos.z, this.centerX, this.centerY, this.centerZ, 0, 0, -1);
      }
    
      public void setVelocity(float newVelocity) {
        this.velocity = newVelocity;
      }
    
      public void setFluidity(float newFluidity) {
        if(newFluidity < 0 || newFluidity > 1) {
          newFluidity = 0.9;
          println("Fluidity requires a value between 0 and 1! New fluidity was set to 0.9 (default).");
        }
        this.fluidity = newFluidity;
      }
    
      private PVector getWindowLocation() {
        PVector l = new PVector();
        com.jogamp.nativewindow.util.Point p = new com.jogamp.nativewindow.util.Point();
        ((com.jogamp.newt.opengl.GLWindow)surface.getNative()).getLocationOnScreen(p);
        l.x = p.getX();
        l.y = p.getY();
        return l;
      }
    
      void keyPressed(){
        if(key == CODED){
          if(keyCode == SHIFT){
            down = true;
          }
        }
        if(key == ' '){
          up = true;
        }
    
        if(key == 'w' || key == 'W'){
          forward = true;
        }
        if(key == 'a' || key == 'A'){
          left = true;
        }
        if(key == 's' || key == 'S'){
          backwards = true;
        }
        if(key == 'd' || key == 'D'){
          right = true;
        }
    
      }
    
      void keyReleased(){
    
        if(key == CODED){
          if(keyCode == SHIFT){
            down = false;
          }
        }
        if(key == ' '){
          up = false;
        }
    
        if(key == 'w' || key == 'W'){
          forward = false;
        }
        if(key == 'a' || key == 'A'){
          left = false;
        }
        if(key == 's' || key == 'S'){
          backwards = false;
        }
        if(key == 'd' || key == 'D'){
          right = false;
        }
    
      }
    
    }
    
  • @mothersmilkk -- thanks for sharing your solution with the forum, and congratulations on writing your own simple camera class!

  • Well done!

    ;-)

  • Thank you guys! Hope this will be useful to someone :D

Sign In or Register to comment.