I'm trying to write an FPS like camera following this tutorial. But when I move my mouse left and right, instead of looking left and right, the camera rotates.
The sphericalToCartesian
function I'm using function comes from this post.
My camera class:
private static final float FOVY = 60f, ZNEAR = .1f, ZFAR = 2000f;
private Mat4 projectionMatrix;
// start out at origin (0,0,0)
private Vec3 position = new Vec3();
// horizontal angle in radians: toward -Z
private float horizontalAngle = (float) FastMath.PI;
// NOTE: tutorial says 0 is horizon
// vertical angle in radians: π/2, look at the horizon
private float verticalAngle = (float) (FastMath.PI / 2.0f);
private float mouseSpeed = 0.01f;
private Vec3 sphericalToCartesian(float yaw, float pitch) {
return new Vec3(
(float) (FastMath.cos(pitch) * FastMath.sin(yaw)),
(float) FastMath.sin(pitch),
(float) (FastMath.cos(pitch) * FastMath.cos(yaw))
);
}
public FPSCamera(Observer o) {
addObserver(o);
}
/**
* Called in GLEventListener.display() and sent to shader with
* glUniformMatrix4fv
*
* @return MPV matrix
*/
public Mat4 getMVPMatrix() {
Vec3 frontVector = sphericalToCartesian(horizontalAngle, verticalAngle);
Vec3 rightVector = sphericalToCartesian((float) (horizontalAngle + FastMath.PI / 2.0f), 0f);
Vec3 upVector = rightVector.cross(frontVector);
Mat4 viewMatrix = Matrices.lookAt(position, position.add(frontVector), upVector);
return projectionMatrix.multiply(viewMatrix);
}
/**
* Called in GLEventListener.reshape()
*
* @param aspect The aspect ratio
*/
public void setPerspective(float aspect) {
projectionMatrix = Matrices.perspective(FOVY, aspect, ZNEAR, ZFAR);
}
/**
* Key and mouse listeners will notify the camera when something happens by
* calling this method.
*/
@Override
public void update(Observable o, Object arg) {
if (o instanceof FPSKeyController) {
final FPSKeyController.Direction[] dirs = (FPSKeyController.Direction[]) arg;
Vec3 right = sphericalToCartesian((float) (horizontalAngle + FastMath.PI / 2.0f), 0f);
Vec3 front = sphericalToCartesian(horizontalAngle, verticalAngle);
// Move forward and backward
if (dirs[0] == FPSKeyController.Direction.FORWARD) {
position = position.add(front);
} else if (dirs[0] == FPSKeyController.Direction.BACKWARD) {
position = position.subtract(front);
}
// Strafe left and right
if (dirs[1] == FPSKeyController.Direction.RIGHT) {
position = position.subtract(right);
} else if (dirs[1] == FPSKeyController.Direction.LEFT) {
position = position.add(right);
}
} else if (o instanceof FPSMouseController) {
final FPSMouseController.Direction[] dirs = (FPSMouseController.Direction[]) arg;
if (dirs[0] == FPSMouseController.Direction.LEFT) {
// Look left
horizontalAngle -= mouseSpeed;
// Let angle range from -2π to 2π
if (horizontalAngle < -FastMath.PI * 2) {
horizontalAngle = 0;
}
} else if (dirs[0] == FPSMouseController.Direction.RIGHT) {
// Look right
horizontalAngle += mouseSpeed;
// Let angle range from -2π to 2π
if (horizontalAngle > FastMath.PI * 2) {
horizontalAngle = 0;
}
}
if (dirs[1] == FPSMouseController.Direction.UP) {
// Look up
// Stop the camera from looking more than straight up
if (verticalAngle + mouseSpeed <= FastMath.PI) {
verticalAngle += mouseSpeed;
}
} else if (dirs[1] == FPSMouseController.Direction.DOWN) {
// Look down
// Stop the camera from looking more than straight down
if (verticalAngle - mouseSpeed >= 0) {
verticalAngle -= mouseSpeed;
}
}
}
// input is guaranteed to change the camera, so we can always update the view
setChanged();
// repaint() and eventually GLEventListener.display() are called at the observer
notifyObservers();
}
I think my problem is the verticalAngle
, in the tutorial it's 0
to look at the horizon. I have to change it to π/2 radians
to look at the horizon. When I look straight down, I can look right and left.