/*! -------------------------------------------------------------------- \file Camera.cpp \brief Class to a encapsulate a camera \author James Kuffner \date 2002-09-20 -------------------------------------------------------------------- */ #ifndef IGNORE_DEPEND #include #include #include #include #endif #include "camera.h" //! default camera setup const float DEFAULT_FOV = 60.0; const float DEFAULT_NEAR_CLIP = 1; const float DEFAULT_FAR_CLIP = 200.0; const float DEFAULT_ASPECT = 1.33333333; //--------------------------------------------------------------------- // Camera // // Method: Constructor // //--------------------------------------------------------------------- Camera::Camera() { _fov = DEFAULT_FOV; _nearClip = DEFAULT_NEAR_CLIP; _farClip = DEFAULT_FAR_CLIP; } void Camera::Init(float w,float h) { assert(w>0 && h>0); _aspectRatio = w/h; } //--------------------------------------------------------------------- // Camera // Method: SetViewingParams // //! function to alter the camera viewing parameters // //--------------------------------------------------------------------- void Camera::SetViewingParams(float fov, float nearClip, float farClip) { assert(fov > 0 && fov < 180); assert(nearClip > 0); assert(farClip > 0); _fov = fov; _nearClip = nearClip; _farClip = farClip; } //--------------------------------------------------------------------- // Camera // Method: SetViewingParams // //! set the aspect ratio // //--------------------------------------------------------------------- void Camera::SetAspectRatio(float aspect){ assert(aspect > 0); _aspectRatio = aspect; } //-------------------------------------------------------------------- // // Camera helper functions // //-------------------------------------------------------------------- void CalculateRelativePosition(PlayerState player, CameraState* camera){ // recalculate camera.dir - the position of camera relative to player // based on current player state and camera state vector3f newdir; newdir = camera->eye - player.loc; newdir = newdir.rotate_z(toRadian(-player.theta)); vector3f up; up.set(0,0,1); // make sure it's parallel to up if (newdir.norm() == up) { //vector3f temp; temp = (camera->eye - dest.eye)*weight; //camera->eye = dest.eye + dir; newdir = newdir*0.9 + camera->dir*0.1; } camera->dir = newdir; } void CalculateGoalPosition(PlayerState player, CameraState* camera){ // calculate camera state based on player state and camera.dir // dir never paralle to up, so at should be safe vector3f dir = camera->dir; dir = dir.rotate_z(toRadian(player.theta)); vector3f p1 = vector3f(0,0,0); vector3f p2 = vector3f(0,1,0); p2 = p2.rotate_z(toRadian(player.theta)); dir = RotateAxisAngle(dir, (float)(toRadian(player.phi-90)), p1, p2); camera->at = player.loc; camera->eye = player.loc + dir; camera->up.set(0, 0, 1); } void CalculateTailingPosition(PlayerState player, CameraState* camera){ float weight = 0.5; //larger closer to camera CameraState dest; vector3f dir; // find desired final position dest.dir = camera->dir; CalculateGoalPosition(player, &dest); dir = (camera->eye - dest.eye)*weight; camera->eye = dest.eye + dir; dir = (camera->at - dest.at)*weight; camera->at = dest.at + dir; camera->up.set(dest.up); } //--------------------------------------------------------------------------- void FixedAttached(PlayerState player, CameraState* camera){ float VIEWDISTANCE = 5; //these ifs prevent the at vector from becoming parallel to the up vector, //assuming 001 is always up. if (player.phi<=0.2) player.phi=0.2; if (player.phi>=179.8) player.phi=179.8; camera->at.x = VIEWDISTANCE*sin(player.phi/57.296)*cos(player.theta/57.296)+player.loc.x; camera->at.y = VIEWDISTANCE*sin(player.phi/57.296)*sin(player.theta/57.296)+player.loc.y; camera->at.z = VIEWDISTANCE*cos(player.phi/57.296)+player.loc.z; camera->eye.x = player.loc.x+(player.loc.x - camera->at.x); camera->eye.y = player.loc.y+(player.loc.y - camera->at.y); camera->eye.z = player.loc.z+(player.loc.z - camera->at.z); camera->up.set(0, 0, 1); //ground plane collision detection //if (eyez<=0.01) eyez=0.01; } void FixedTailing(PlayerState player, CameraState* camera){ float weight = 0.98; //larger closer to camera CameraState dest; vector3f dir; //find desired final position FixedAttached(player, &dest); dir = (camera->eye - dest.eye)*weight; camera->eye = dest.eye + dir; dir = (camera->at - dest.at)*weight; camera->at = dest.at + dir; camera->up.set(dest.up); } //-------------------------------------------------------------------- // Camera // // Method: SetView // //! load the viewing transformations on the matrix stacks // //--------------------------------------------------------------------- // camera is pass by ref and player is a copy void Camera::SetView(PlayerState player, CameraState* camera){ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(_fov, _aspectRatio, _nearClip, _farClip); switch(camera->mode){ case ADJUST_CAMERA: CalculateRelativePosition(player, camera); break; case TAILING_CAMERA: CalculateTailingPosition(player, camera); //FixedTailing(player, camera); break; case DETACHED_CAMERA: //don't need to do anything break; case ATTACHED_CAMERA: default: CalculateGoalPosition(player, camera); //FixedAttached(player, camera); break; } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(V3COMP(camera->eye), V3COMP(camera->at), V3COMP(camera->up)); }