The quaternion cameraTo make a camera you typically use three vectors: Position, View, and Up (or you may call them what you like). For a first person camera - which we will be using - we're only going to consider rotating the View vector. With quaternions we can rotate a vector around an arbitrary axis (same as with axis-angles) very easily. To achieve this, first we need to turn our View vector into a quaternion, then define a rotation quaternion and lastly, apply the rotation quaternion to the View quaternion to make the rotation. To make the View quaternion, V, the x, y, and z values are taken from the View vector and we simply add a 0 for the scalar component w. Thus, V = [0, View] Then you need to make a quaternion to represent the rotation. To do this, you need the vector you want to rotate about, and the angle you wish to rotate by. We'll just simply term the vector to rotate about A, and the angle theta. Here is the formula to build your rotation quaternion, which we'll call R. vector A = [x, y, z] R.x = A.x * sin(theta/2) R.y = A.y * sin(theta/2) R.z = A.z * sin(theta/2) R.w = cos(theta/2) So now we have the vector (View) and its quaternion V that we want to rotate by an angle theta about the vector A. The rotation quaternion R defines this rotation. After the rotation, we'll have the new quaternion representing our view, given by W. The rotation operation is simply W = R * V * R' where R' is the conjugate of R. To get our new view vector, we just take the vector components out of W. NewView = [W.x W.y W.z] The following function (using SDL, use glut or whatever you like) sets the view based on the distance from the current mouse coordinates to the centre of the screen. I learned how to do this from gametutorials.com, and modified the code for my purposes. In this code, positive x is to the right and positive y is down the screen. void Camera::SetViewByMouse(void) { // the coordinates of our mouse coordinates int MouseX, MouseY; // the middle of the screen in the x direction int MiddleX = SCREENWIDTH/2; // the middle of the screen in the y direction int MiddleY = SCREENHEIGHT/2; // vector that describes mouseposition - center Vector MouseDirection(0, 0, 0); // static variable to store the rotation about the x-axis, since // we want to limit how far up or down we can look. // We don't need to cap the rotation about the y-axis as we // want to be able to turn around 360 degrees static double CurrentRotationAboutX = 0.0; // The maximum angle we can look up or down, in radians double maxAngle = 1; // This function gets the position of the mouse SDL_GetMouseState(&MouseX, &MouseY); // if the mouse hasn't moved, return without doing // anything to our view if((MouseX == MiddleX) && (MouseY == MiddleY)) return; // otherwise move the mouse back to the middle of the screen SDL_WarpMouse(MiddleX, MiddleY); // get the distance and direction the mouse moved in x (in // pixels). We can't use the actual number of pixels in radians, // as only six pixels would cause a full 360 degree rotation. // So we use a mousesensitivity variable that can be changed to // vary how many radians we want to turn in the x-direction for // a given mouse movement distance // We have to remember that positive rotation is counter-clockwise. // Moving the mouse down is a negative rotation about the x axis // Moving the mouse right is a negative rotation about the y axis MouseDirection.x = (MiddleX - MouseX)/MouseSensitivity; MouseDirection.y = (MiddleY - MouseY)/MouseSensitivity; CurrentRotationX += MouseDirection.y; // We don't want to rotate up more than one radian, so we cap it. if(CurrentRotationX > 1) { CurrentRotationX = 1; return; } // We don't want to rotate down more than one radian, so we cap it. if(CurrentRotationX < -1) { CurrentRotationX = -1; return; } else { // get the axis to rotate around the x-axis. Vector Axis = CrossProduct(View - Position, Up); // To be able to use the quaternion conjugate, the axis to // rotate around must be normalized. Axis = Normalize(Axis); // Rotate around the y axis RotateCamera(MouseDirection.y, Axis.x, Axis.y, Axis.z); // Rotate around the x axis RotateCamera(MouseDirection.x, 0, 1, 0); } } This function actually rotates our view. After we are done, just plug your camera vectors (Position, View, and Up) into gluLookAt(Position.x, Position.y, Position.z, View.x, View.y, View.z, Up.x, Up.y, Up.z). Here is the code for the rotation. void RotateCamera(double Angle, double x, double y, double z) { quaternion temp, quat_view, result; temp.x = x * sin(Angle/2); temp.y = y * sin(Angle/2); temp.z = z * sin(Angle/2); temp.w = cos(Angle/2); quat_view.x = View.x; quat_view.y = View.y; quat_view.z = View.z; quat_view.w = 0; result = mult(mult(temp, quat_view), conjugate(temp)); View.x = result.x; View.y = result.y; View.z = result.z; } Again, at the end of the above functions, you should call gluLookAt(Position.x, Position.y, Position.z, View.x, View.y, View.z, Up.x, Up.y, Up.z). and your camera should work just perfectly. Maybe some other time, I'll do a third person camera tutorial, and explain how to use SLERP.
|
|