#include "rtsCameraController.h" #include rtsCamera::rtsCamera() { position = point3D(0, 0, 0); view_vector = vector3D(0, 0, -1); up_vector = vector3D(0, 1, 0); lookat_point = point3D(0, 0, -1); pers_view_angle = 60; ortho_width = 1.0; ortho_height = 1.0; near_plane = 1; far_plane = 100; } rtsCamera::LookAt( /* rtsCamera::rtsCamera(rtsCameraState initial_state) { m_camera_state = initial_state; //make sure that the view and lookat vectors are orthogonal vector3D lookat = m_camera_state.lookat - m_camera_state.position; vector3D up = m_camera_state.up; vector3D side = lookat.X(up); up = side.X(lookat); up.Normalize(); m_camera_state.up = up; } rtsCameraState rtsCamera::getState() { return m_camera_state; } void rtsCamera::setState(rtsCameraState camera_state) { m_camera_state = camera_state; //re-orthogonalize the vectors vector3D view = m_camera_state.lookat - m_camera_state.position; vector3D side = view.X(m_camera_state.up); m_camera_state.up = side.X(view); m_camera_state.up.Normalize(); } void rtsCamera::LookAt(point3D point) { //looks at a point //find the new view vector vector3D view = point - m_camera_state.position; //normalize the view vector view.Normalize(); //prepare a new side vector and up vector vector3D side; vector3D up; //get the up vector //if the new viewvector is at 0 or 180 degrees to the up vector float cos_angle = view*m_camera_state.up; if(cos_angle == 1.0f || cos_angle == -1.0f) { //re-calculate the up vector up = m_camera_state.up.X(m_camera_state.lookat - m_camera_state.position); } else { //otherwise, just get the current up vector up = m_camera_state.up; } //correct the up vector based on the new view vector side = up.X(view); up = view.X(side); up.Normalize(); //change the camera state m_camera_state.up = up; m_camera_state.lookat = point; } void rtsCamera::Position(point3D p) { m_camera_state.position = p; } void rtsCamera::Up(vector3D up) { m_camera_state.up = up; } void rtsCamera::DollyPosition(point3D p) { vector3D adjustment = p-m_camera_state.position; m_camera_state.position = p; m_camera_state.lookat = m_camera_state.lookat + adjustment; } point3D rtsCamera::getLookAtPoint() { return m_camera_state.lookat; } void rtsCamera::Pan(double x, double y) { //first calculate the lookat and side vectors vector3D lookatvector=m_camera_state.lookat - m_camera_state.position; vector3D sidevector = lookatvector.X(m_camera_state.up); sidevector.Normalize(); m_camera_state.position=m_camera_state.position+sidevector*x; m_camera_state.lookat=m_camera_state.lookat+sidevector*x; vector3D upvector = lookatvector.X(sidevector); upvector.Normalize(); m_camera_state.position=m_camera_state.position+upvector*y; m_camera_state.lookat=m_camera_state.lookat+upvector*y; } void rtsCamera::RotateUpDown(double degrees) { //first calculate the lookat and side vectors vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; vector3D sidevector = lookatvector.X(m_camera_state.up); m_camera_state.up=sidevector.X(lookatvector); m_camera_state.up.Normalize(); sidevector.Normalize(); //translate the look-at point to the origin (and the camera with it) point3D origin = point3D(0.0, 0.0, 0.0); vector3D translateCamera = origin-m_camera_state.lookat; point3D translatedCamera=m_camera_state.position+translateCamera; //the next step is to rotate the side vector so that it lines up with the z axis double a=sidevector.x; double b=sidevector.y; double c=sidevector.z; double d=sqrt(b*b + c*c); //error correction for when we are already looking down the z-axis if(d==0) return; vector3D XZplane = vector3D(translatedCamera.x, (translatedCamera.y*c/d - translatedCamera.z*b/d), (translatedCamera.y*b/d + translatedCamera.z*c/d)); vector3D Zaxis = vector3D(XZplane.x*d - XZplane.z*a, XZplane.y, XZplane.x*a + XZplane.z*d); vector3D rotated = vector3D(Zaxis.x*cos(TORADIANS(degrees)) - Zaxis.y*sin(TORADIANS(degrees)), Zaxis.x*sin(TORADIANS(degrees)) + Zaxis.y*cos(TORADIANS(degrees)), Zaxis.z); vector3D XZout = vector3D( rotated.x*(d/(a*a + d*d)) + rotated.z*(a/(a*a + d*d)), rotated.y, rotated.x*(-a/(a*a+d*d)) + rotated.z*(d/(a*a + d*d))); vector3D result = vector3D( XZout.x, XZout.y*(c*d/(b*b + c*c)) + XZout.z*(b*d/(b*b + c*c)), XZout.y*(-b*d/(b*b + c*c)) + XZout.z*(c*d/(b*b + c*c))); result=result-translateCamera; m_camera_state.position.x=result.x; m_camera_state.position.y=result.y; m_camera_state.position.z=result.z; } void rtsCamera::Yaw(double degrees) { //basically, we have to rotate the look-at point around the up vector //first, translate the look-at point so that the camera is at the origin point3D origin(0.0, 0.0, 0.0); point3D temp_lookat = m_camera_state.lookat - (m_camera_state.position - origin); //create a rotation matrix to rotate the lookat point around the up vector float x=m_camera_state.up.x; float y=m_camera_state.up.y; float z=m_camera_state.up.z; float c=cos(TORADIANS(-degrees)); float s=sin(TORADIANS(-degrees)); float t=1.0 - cos(TORADIANS(-degrees)); float m00 = t*x*x + c; float m01 = t*x*y + s*z; float m02 = t*x*z - s*y; float m03 = 0; float m10 = t*x*y - s*z; float m11 = t*y*y + c; float m12 = t*y*z + s*x; float m13 = 0; float m20 = t*x*z + s*y; float m21 = t*y*z - s*x; float m22 = t*z*z + c; float m23 = 0; float m30 = 0; float m31 = 0; float m32 = 0; float m33 = 1; matrix4x4 rotation(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33); point3D result = rotation*temp_lookat + (m_camera_state.position - origin); m_camera_state.lookat = result; } void rtsCamera::Pitch(double degrees) { //basically, we have to rotate the look-at point and up vector around the side vector //first, translate the look-at point so that the camera is at the origin point3D origin(0.0, 0.0, 0.0); //find all three necessary vectors vector3D temp_lookat = m_camera_state.lookat - m_camera_state.position; double lookat_length = temp_lookat.Length(); vector3D temp_up = m_camera_state.up; vector3D temp_side = temp_lookat.X(temp_up); temp_lookat.Normalize(); temp_up.Normalize(); temp_side.Normalize(); //create a rotation matrix to rotate around the side vector float x=temp_side.x; float y=temp_side.y; float z=temp_side.z; float c=cos(TORADIANS(degrees)); float s=sin(TORADIANS(degrees)); float t=1.0 - cos(TORADIANS(degrees)); float m00 = t*x*x + c; float m01 = t*x*y + s*z; float m02 = t*x*z - s*y; float m03 = 0; float m10 = t*x*y - s*z; float m11 = t*y*y + c; float m12 = t*y*z + s*x; float m13 = 0; float m20 = t*x*z + s*y; float m21 = t*y*z - s*x; float m22 = t*z*z + c; float m23 = 0; float m30 = 0; float m31 = 0; float m32 = 0; float m33 = 1; matrix4x4 rotation(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33); //rotate the up and look-at vectors around the side vector vector3D result_lookat = rotation*temp_lookat; vector3D result_up = rotation*temp_up; result_lookat.Normalize(); result_up.Normalize(); m_camera_state.lookat = m_camera_state.position + result_lookat * lookat_length; m_camera_state.up = result_up; } void rtsCamera::RotateLeftRight(double degrees) //this function rotates the camera around the up vector (which always points along hte positive //Y world axis). { //translate the look-at point to the origin (and the camera with it) point3D origin = point3D(0.0, 0.0, 0.0); vector3D translateCamera = origin-m_camera_state.lookat; point3D translatedCamera=m_camera_state.position+translateCamera; //perform the rotation around the look-at point //using the y-axis as the rotation axis point3D newcamera; newcamera.x=translatedCamera.x*cos(TORADIANS(degrees)) - translatedCamera.z*sin(TORADIANS(degrees)); newcamera.z=translatedCamera.x*sin(TORADIANS(degrees)) + translatedCamera.z*cos(TORADIANS(degrees)); newcamera.y=translatedCamera.y; vector3D newup; newup.x=m_camera_state.up.x*cos(TORADIANS(degrees)) - m_camera_state.up.z*sin(TORADIANS(degrees)); newup.z=m_camera_state.up.x*sin(TORADIANS(degrees)) + m_camera_state.up.z*cos(TORADIANS(degrees)); newup.y=m_camera_state.up.y; //translate the lookat point back to it's original position (along with the camera) newcamera=newcamera-translateCamera; m_camera_state.position.x=newcamera.x; m_camera_state.position.y=newcamera.y; m_camera_state.position.z=newcamera.z; m_camera_state.up.x=newup.x; m_camera_state.up.y=newup.y; m_camera_state.up.z=newup.z; m_camera_state.up.Normalize(); } void rtsCamera::Forward(double distance) { //calculate the lookat vector (direction of travel) vector3D old_lookat=m_camera_state.lookat-m_camera_state.position; old_lookat.Normalize(); //calculate the new position of the camera point3D new_position = m_camera_state.position+old_lookat*distance; //now calculate the new lookat vector vector3D new_lookat=m_camera_state.lookat-new_position; //find the length of the new lookat vector //move the camera to the new position m_camera_state.position = new_position; } void rtsCamera::ScaleForward(double factor, double min, double max) { //This function moves the camera forward, scaling the magnitude //of the motion by the length of the view vector. Basically, the closer //the camera is to the lookat point, the slower the camera moves. //calculate the lookat vector (direction of travel) vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; //find the length of the view vector double length = lookatvector.Length(); //normalize lookatvector.Normalize(); //prevent motion if the bounds would be passed double new_distance = length - (factor*length); if(new_distance < min || new_distance > max) factor = 0; //move the camera m_camera_state.position=m_camera_state.position+lookatvector*factor*length; lookatvector=m_camera_state.lookat-m_camera_state.position; } void rtsCamera::DollyLeftRight(double distance) { //calculate the side vector vector (direction of travel) vector3D lookatvector=m_camera_state.lookat-m_camera_state.position; vector3D side = lookatvector.X(m_camera_state.up); side.Normalize(); m_camera_state.position=m_camera_state.position+side*distance; m_camera_state.lookat = m_camera_state.lookat + side*distance; //lookatvector=m_camera_state.lookat-m_camera_state.position; } void rtsCamera::DollyUpDown(double distance) { //move along the up vector m_camera_state.up.Normalize(); m_camera_state.position=m_camera_state.position+m_camera_state.up*distance; m_camera_state.lookat = m_camera_state.lookat + m_camera_state.up*distance; //lookatvector=m_camera_state.lookat-m_camera_state.position; } void rtsCamera::Zoom(double angle) { m_camera_state.pers_view_angle += angle; } */