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