www.pudn.com > FrustumCulling.rar > Camera.cpp
//***********************************************************************// // // // - "Talk to me like I'm a 3 year old!" Programming Lessons - // // // // $Author: DigiBen digiben@gametutorials.com // // // // $Program: Frustum Culling // // // // $Description: Demonstrates checking if shapes are in view // // // // $Date: 8/28/01 // // // //***********************************************************************// #pragma comment(lib, "winmm.lib") // Added for timeGetTime() #include "main.h" #include "Camera.h" # include// We increased the speed a bit from the Camera Strafing Tutorial // This is how fast our camera moves #define kSpeed 50.0f // Our global float that stores the elapsed time between the current and last frame float g_FrameInterval = 0.0f; ///////////////////////////////// CALCULATE FRAME RATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This function calculates the frame rate and time intervals between frames ///// ///////////////////////////////// CALCULATE FRAME RATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* void CalculateFrameRate() { static float framesPerSecond = 0.0f; // This will store our fps static float lastTime = 0.0f; // This will hold the time from the last frame static char strFrameRate[50] = {0}; // We will store the string here for the window title static float frameTime = 0.0f; // This stores the last frame's time // Get the current time in seconds float currentTime = SDL_GetTicks() * 0.001f; // Here we store the elapsed time between the current and last frame, // then keep the current frame in our static variable for the next frame. g_FrameInterval = currentTime - frameTime; frameTime = currentTime; // Increase the frame counter ++framesPerSecond; // Now we want to subtract the current time by the last time that was stored // to see if the time elapsed has been over a second, which means we found our FPS. if( currentTime - lastTime > 1.0f ) { // Here we set the lastTime to the currentTime lastTime = currentTime; // Copy the frames per second into a string to display in the window title bar sprintf(strFrameRate, "Current Frames Per Second: %d", int(framesPerSecond)); /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // Commented out for this tutorialwwwwwwwwww // Set the window title bar to our string //SetWindowText(g_hWnd, strFrameRate); /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // Reset the frames per second framesPerSecond = 0; } } /////////////////////////////////////// CROSS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This returns a perpendicular vector from 2 given vectors by taking the cross product. ///// /////////////////////////////////////// CROSS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* CVector3 Cross(CVector3 vVector1, CVector3 vVector2) { CVector3 vNormal; // Calculate the cross product with the non communitive equation vNormal.x = ((vVector1.y * vVector2.z) - (vVector1.z * vVector2.y)); vNormal.y = ((vVector1.z * vVector2.x) - (vVector1.x * vVector2.z)); vNormal.z = ((vVector1.x * vVector2.y) - (vVector1.y * vVector2.x)); // Return the cross product return vNormal; } /////////////////////////////////////// MAGNITUDE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This returns the magnitude of a vector ///// /////////////////////////////////////// MAGNITUDE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* float Magnitude(CVector3 vNormal) { // Here is the equation: magnitude = sqrt(V.x^2 + V.y^2 + V.z^2) : Where V is the vector return (float)sqrt( (vNormal.x * vNormal.x) + (vNormal.y * vNormal.y) + (vNormal.z * vNormal.z) ); } /////////////////////////////////////// NORMALIZE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This returns a normalize vector (A vector exactly of length 1) ///// /////////////////////////////////////// NORMALIZE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* CVector3 Normalize(CVector3 vVector) { // Get the magnitude of our normal float magnitude = Magnitude(vVector); // Now that we have the magnitude, we can divide our vector by that magnitude. // That will make our vector a total length of 1. vVector = vVector / magnitude; // Finally, return our normalized vector return vVector; } ///////////////////////////////// CCAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This is the class constructor ///// ///////////////////////////////// CCAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* CCamera::CCamera() { CVector3 vZero = CVector3(0.0, 0.0, 0.0); // Init a vector to 0 0 0 for our position CVector3 vView = CVector3(0.0, 1.0, 0.5); // Init a starting view vector (looking up and out the screen) CVector3 vUp = CVector3(0.0, 0.0, 1.0); // Init a standard up vector (Rarely ever changes) m_vPosition = vZero; // Init the position to zero m_vView = vView; // Init the view to a std starting view m_vUpVector = vUp; // Init the UpVector } ///////////////////////////////// POSITION CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This function sets the camera's position and view and up vector. ///// ///////////////////////////////// POSITION CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* void CCamera::PositionCamera(float positionX, float positionY, float positionZ, float viewX, float viewY, float viewZ, float upVectorX, float upVectorY, float upVectorZ) { CVector3 vPosition = CVector3(positionX, positionY, positionZ); CVector3 vView = CVector3(viewX, viewY, viewZ); CVector3 vUpVector = CVector3(upVectorX, upVectorY, upVectorZ); // The code above just makes it cleaner to set the variables. // Otherwise we would have to set each variable x y and z. m_vPosition = vPosition; // Assign the position m_vView = vView; // Assign the view m_vUpVector = vUpVector; // Assign the up vector } ///////////////////////////////// SET VIEW BY MOUSE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This allows us to look around using the mouse, like in most first person games. ///// ///////////////////////////////// SET VIEW BY MOUSE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* void CCamera::SetViewByMouse() { int mousePos_x,mousePos_y; int middleX = SCREEN_WIDTH >> 1; // This is a binary shift to get half the width int middleY = SCREEN_HEIGHT >> 1; // This is a binary shift to get half the height float angleY = 0.0f; // This is the direction for looking up or down float angleZ = 0.0f; // This will be the value we need to rotate around the Y axis (Left and Right) static float currentRotX = 0.0f; // Get the mouse's current X,Y position SDL_GetMouseState(&mousePos_x,&mousePos_y); // If our cursor is still in the middle, we never moved... so don't update the screen if( (mousePos_x == middleX) && (mousePos_y == middleY) ) return; // Set the mouse position to the middle of our window SDL_WarpMouse(middleX,middleY); // Get the direction the mouse moved in, but bring the number down to a reasonable amount angleY = (float)( (middleX - mousePos_x) ) / 500.0f; angleZ = (float)( (middleY - mousePos_y) ) / 500.0f; // Here we keep track of the current rotation (for up and down) so that // we can restrict the camera from doing a full 360 loop. currentRotX -= angleZ; // If the current rotation (in radians) is greater than 1.0, we want to cap it. if(currentRotX > 1.0f) currentRotX = 1.0f; // Check if the rotation is below -1.0, if so we want to make sure it doesn't continue else if(currentRotX < -1.0f) currentRotX = -1.0f; // Otherwise, we can rotate the view around our position else { // To find the axis we need to rotate around for up and down // movements, we need to get a perpendicular vector from the // camera's view vector and up vector. This will be the axis. CVector3 vAxis = Cross(m_vView - m_vPosition, m_vUpVector); vAxis = Normalize(vAxis); // Rotate around our perpendicular axis and along the y-axis RotateView(angleZ, vAxis.x, vAxis.y, vAxis.z); } // Rotate around the y axis no matter what the currentRotX is RotateView(angleY, 0, 1, 0); } ///////////////////////////////// ROTATE VIEW \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This rotates the view around the position using an axis-angle rotation ///// ///////////////////////////////// ROTATE VIEW \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* void CCamera::RotateView(float angle, float x, float y, float z) { CVector3 vNewView; // Get the view vector (The direction we are facing) CVector3 vView = m_vView - m_vPosition; // Calculate the sine and cosine of the angle once float cosTheta = (float)cos(angle); float sinTheta = (float)sin(angle); // Find the new x position for the new rotated point vNewView.x = (cosTheta + (1 - cosTheta) * x * x) * vView.x; vNewView.x += ((1 - cosTheta) * x * y - z * sinTheta) * vView.y; vNewView.x += ((1 - cosTheta) * x * z + y * sinTheta) * vView.z; // Find the new y position for the new rotated point vNewView.y = ((1 - cosTheta) * x * y + z * sinTheta) * vView.x; vNewView.y += (cosTheta + (1 - cosTheta) * y * y) * vView.y; vNewView.y += ((1 - cosTheta) * y * z - x * sinTheta) * vView.z; // Find the new z position for the new rotated point vNewView.z = ((1 - cosTheta) * x * z - y * sinTheta) * vView.x; vNewView.z += ((1 - cosTheta) * y * z + x * sinTheta) * vView.y; vNewView.z += (cosTheta + (1 - cosTheta) * z * z) * vView.z; // Now we just add the newly rotated vector to our position to set // our new rotated view of our camera. m_vView = m_vPosition + vNewView; } ///////////////////////////////// STRAFE CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This strafes the camera left and right depending on the speed (-/+) ///// ///////////////////////////////// STRAFE CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* void CCamera::StrafeCamera(float speed) { // Add the strafe vector to our position m_vPosition.x += m_vStrafe.x * speed; m_vPosition.z += m_vStrafe.z * speed; // Add the strafe vector to our view m_vView.x += m_vStrafe.x * speed; m_vView.z += m_vStrafe.z * speed; } ///////////////////////////////// MOVE CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This will move the camera forward or backward depending on the speed ///// ///////////////////////////////// MOVE CAMERA \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* void CCamera::MoveCamera(float speed) { // Get the current view vector (the direction we are looking) CVector3 vVector = m_vView - m_vPosition; vVector = Normalize(vVector); m_vPosition.x += vVector.x * speed; // Add our acceleration to our position's X m_vPosition.y += vVector.y * speed; // Add our acceleration to our position's Y m_vPosition.z += vVector.z * speed; // Add our acceleration to our position's Z m_vView.x += vVector.x * speed; // Add our acceleration to our view's X m_vView.y += vVector.y * speed; // Add our acceleration to our view's Y m_vView.z += vVector.z * speed; // Add our acceleration to our view's Z } //////////////////////////// CHECK FOR MOVEMENT \\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This function handles the input faster than in the WinProc() ///// //////////////////////////// CHECK FOR MOVEMENT \\\\\\\\\\\\\\\\\\\\\\\\\\\\* void CCamera::CheckForMovement() { // Once we have the frame interval, we find the current speed float speed = kSpeed * g_FrameInterval; Uint8 *keyState = SDL_GetKeyState(NULL); // Check if we hit the Up arrow or the 'w' key if(keyState[SDLK_UP] || keyState[SDLK_w] ) { // Move our camera forward by a positive SPEED MoveCamera(speed); } // Check if we hit the Down arrow or the 's' key if(keyState[SDLK_DOWN] || keyState[SDLK_s] ) { // Move our camera backward by a negative SPEED MoveCamera(-speed); } // Check if we hit the Left arrow or the 'a' key if(keyState[SDLK_LEFT] || keyState[SDLK_a]) { // Strafe the camera left StrafeCamera(-speed); } // Check if we hit the Right arrow or the 'd' key if(keyState[SDLK_RIGHT] || keyState[SDLK_d]) { // Strafe the camera right StrafeCamera(speed); } } ///////////////////////////////// UPDATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This updates the camera's view and strafe vector ///// ///////////////////////////////// UPDATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* void CCamera::Update() { // Initialize a variable for the cross product result CVector3 vCross = Cross(m_vView - m_vPosition, m_vUpVector); // Normalize the strafe vector m_vStrafe = Normalize(vCross); // Move the camera's view by the mouse SetViewByMouse(); /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // We commented this line out so the camera can't move around // in this tutorial. // This checks to see if the keyboard was pressed //CheckForMovement(); /////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// * // Calculate our frame rate and set our frame interval for time-based movement CalculateFrameRate(); } ///////////////////////////////// LOOK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* ///// ///// This updates the camera according to the ///// ///////////////////////////////// LOOK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\* void CCamera::Look() { // Give openGL our camera position, then camera view, then camera up vector gluLookAt(m_vPosition.x, m_vPosition.y, m_vPosition.z, m_vView.x, m_vView.y, m_vView.z, m_vUpVector.x, m_vUpVector.y, m_vUpVector.z); } ///////////////////////////////////////////////////////////////////////////////// // // * QUICK NOTES * // // Nothing was changed for the camera code in this tutorial except that // we commented out the line that checks for keyboard movement in Update(). // We also commented out the SetWindowText() function in CalculateFrameRate(). // // // Ben Humphrey (DigiBen) // Game Programmer // DigiBen@GameTutorials.com // Co-Web Host of www.GameTutorials.com // //