3
\$\begingroup\$

First off, I'm sorry if there are duplicates of this. I did an extensive Google search but was unable to find anything that made sense to me. (I am new to 3D rendering and such.)

I want to make a first person camera that the user can control with the mouse. My current implmentation in Processing looks like this:

PMatrix3D cam;
int oldMouseX=0, oldMouseY=0;
void setup(){
    // ...
    cam = new PMatrix3D();
}
void draw(){
    // ...
    int deltaX=oldMouseX-mouseX;
    int deltaY=oldMouseY-mouseY;
    oldMouseX=mouseX;
    oldMouseY=mouseY;
    cam.rotateY((PI/600)*deltaX);
    cam.rotateX((PI/600)*deltaY);
    PVector x = cam.mult(new PVector(1, 0, 0), new PVector(0, 0, 0));
    PVector y = cam.mult(new PVector(0, 1, 0), new PVector(0, 0, 0));
    PVector d = x.cross(y); d.normalize(); d.mult(R);
    float fov = PI/3.0;
    float cameraZ = (height/2.0) / tan(fov/2.0);
    perspective(fov, float(width)/float(height), cameraZ/10.0, cameraZ*1000.0);
    camera(0, 0, 0, d.x, d.y, d.z, y.x, y.y, y.z);
    // render objects
}

It works well, but there is a problem. When the mouse is moved along the x-axis of the screen, and then the y-axis, or in some way one axis at a time, the camera rolls. I understand that 3D rotation is supposed to work like that, 2 consecutive rotations around 2 axes make a rotation around the third. The problem is that once the camera is in this rolled state, it is difficult to get it to be straight again.

How can I make it so it is easy to point the camera in any direction? Please explain in easy to understand terms, if possible.

Also, I am a bit confused on

cam.rotateY((PI/600)*deltaX);
cam.rotateX((PI/600)*deltaY);

Before, I had it as

cam.rotateX((PI/600)*deltaX);
cam.rotateY((PI/600)*deltaY);

But that cause the x and y axes to be switched. (i.e., moving the mouse horizontally caused the camera to rotate vertically.) Why is this?

\$\endgroup\$
5
  • \$\begingroup\$ Judging by the amount of new posts on Stack Overflow, I think a lot of people have time on their hands to code during Christmas. Especially non Christians. \$\endgroup\$
    – DankMemes
    Dec 24, 2013 at 20:24
  • \$\begingroup\$ Well, "Happy Holidays" then :P \$\endgroup\$
    – Moo-Juice
    Dec 24, 2013 at 20:25
  • \$\begingroup\$ peasycam is a library for that... If you like :) \$\endgroup\$
    – v.k.
    Dec 25, 2013 at 0:09
  • \$\begingroup\$ Thanks! I'll try it. But in the meantime can you explain how this is supposed to work? \$\endgroup\$
    – DankMemes
    Dec 26, 2013 at 23:04
  • \$\begingroup\$ it seems you are having a gimbal lock, but I am not 100% sure from your description. Maybe you need to check this gamedev.stackexchange.com/questions/67199/… \$\endgroup\$
    – concept3d
    Dec 29, 2013 at 8:47

1 Answer 1

1
\$\begingroup\$

You can use just the camera() method to change the perspective more easily.

To use it, you probably want two variables: rotationAngle and elevationAngle. Moving the mouse sideways changes rotationAngle between 0 and TWO_PI. You can then set variable centerY to sin(rotationAngle) and centerX to cos(rotationAngle). Moving the mouse up and down would change elevationAngle to anywhere between 0 and PI. Multiply centerX and centerY by sin(elevationAngle) and set centerZ to -cos(elevationAngle). You can then call camera() with the calculated values.

Final code:

float rotationAngle;
float elevationAngle;

float centerX;
float centerY;
float centerZ;

void setup() {
  // ...
}

void draw() {
  // ...
  updateCamera();
  // render objects
}

void updateCamera() {
  rotationAngle = map(mouseX, 0, width, 0, TWO_PI);
  elevationAngle = map(mouseY, 0, height, 0, PI);

  centerX = cos(rotationAngle) * sin(elevationAngle);
  centerY = sin(rotationAngle) * sin(elevationAngle);
  centerZ = -cos(elevationAngle);

  camera(0, 0, 0, centerX, centerY, centerZ, 0, 0, 1);
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .