I am implementing a camera in opengl for an android game and am having problems getting the pitch/yaw/roll of the camera correct. I have read many tutorials on quaternions and have implemented a basic camera based on this link.
Everything works well except for when I pitch and yaw I get unwanted roll. I have read things that say I need to apply the pitch/yaw rotation together to prevent this, and other things that said not to track individual changes to angles, but I'm not sure what they mean or how to extend this implementation to mine. I am new to this type of math so any help would be appreciated.
My goal is to have a camera that can rotate similar to how a space ship would rotate - I want the camera to be able to rotate 360 degrees in all directions and turn upside-down - which is why I was rotating the upVector too.
Any suggestions on what I can do to not have the camera roll when rotating around the y and y axes?
Thanks!
Here is the code that translates user input into two angles, and rotates the lookVector, upVector, and rightVector of the camera. My problem is the camera is also rolling when I just pitch and yaw.
// Java
// Camera uses a position vector, lookAt vector, and upVector
// eventually calls Matrix.setLookAtM()
Camera c = mRenderer.theCamera;
// PVector is a class that implements a 3 dimensional vector
float thetaX = getTouchChange(...); // set by the user touching the screen
float thetaY = getTouchChange(...); // set by the user touching the screen
// I keep 3 vectors in the camera class, one points up, one points right,
// and the 3rd is the point I am looking at
///////////////////////////////////////////////
// Pitch - rotate the up and look around right
///////////////////////////////////////////////
// get up and look vectors
PVector lookVector = PVector.sub(c.getLookAtPoint(), c.getLocation());
PVector otherVector = c.getUpDirection();
// get axis
PVector rAxis = c.getRightDirection();
rAxis.normalize();
// rotate look
PVector rotated = Quaternion.rotateVector(lookVector, rAxis, thetaY);
// Add back camera location to convert vector to actual look points
rotated.add(mRenderer.theCamera.getLocation());
c.setLookAtPoint(rotated);
// rotate up
rotated = Quaternion.rotateVector(otherVector, rAxis, thetaY);
rotated.normalize();
c.setUpDirection(rotated);
///////////////////////////////////////////////
// Yaw - rotate the look and right around up
///////////////////////////////////////////////
// get up and look vectors
lookVector = PVector.sub(c.getLookAtPoint(), c.getLocation());
otherVector = c.getRightDirection();
// get axis
rAxis = c.getUpDirection();
rAxis.normalize();
// rotate look
rotated = Quaternion.rotateVector(lookVector, rAxis, thetaX);
// Add back camera location to convert vector to actual look points
rotated.add(mRenderer.theCamera.getLocation());
c.setLookAtPoint(rotated);
// rotate right
rotated = Quaternion.rotateVector(otherVector, rAxis, thetaX);
rotated.normalize();
c.setRightDirection(rotated);
In my rendering code I update the camera orientation by calling the following
// called in onSurfaceChanged
Matrix.frustumM(m3DProjectionMatrix, 0, -screenRatio, screenRatio, -1, 1, 1, 70);
// called in onDrawFrame
Matrix.setLookAtM(m3DViewMatrix, 0,
theCamera.getLocation().x, theCamera.getLocation().y, theCamera.getLocation().z,
theCamera.getLookAtPoint().x, theCamera.getLookAtPoint().y, theCamera.getLookAtPoint().z,
theCamera.getUpDirection().x, theCamera.getUpDirection().y, theCamera.getUpDirection().z);
Matrix.multiplyMM(m3DMVPMatrix, 0, m3DProjectionMatrix, 0, m3DViewMatrix, 0);
// m3DMVPMatrix is eventually passed to the shader along with the shape data