#include "common.h" #include "Camera.h" #include "glInterface.h" namespace CHCDemoEngine { using namespace std; // this is the start vector. // warning: our coordinate system has the negative z axis pointing up // which is different from the system used in opengl!! static Vector3 startVector = Vector3(0, 1, 0); Camera::Camera() { mWidth = 100; mHeight = 100; mFovy = 60.0f * M_PI / 180.0f; mIsOrtho = false; SetPosition(Vector3(0, 0, 0)); mPitch = mYaw = 0; Precompute(startVector); CalculateFromPitchAndYaw(); } Camera::Camera(int width, int height, float fieldOfView) { mWidth = width; mHeight = height; mFovy = fieldOfView * M_PI / 180.0f; mIsOrtho = false; SetPosition(Vector3(0, 0, 0)); mPitch = mYaw = 0; Precompute(startVector); CalculateFromPitchAndYaw(); } void Camera::Precompute(const Vector3 &direction) { Vector3 up = Vector3(0, 0, 1); Vector3 right = Normalize(CrossProd(up, direction)); up = Normalize(CrossProd(direction, right)); mBaseOrientation = Matrix4x4(right, up, direction); mViewOrientation = mBaseOrientation; } void Camera::SetPosition(const Vector3 &pos) { mPosition = pos; } void Camera::SetNear(float nearDist) { mNear = nearDist; } void Camera::SetFar(float farDist) { mFar = farDist; } void Camera::GetProjectionMatrix(Matrix4x4 &mat) { glGetFloatv(GL_PROJECTION_MATRIX, (float *)mat.x); } void Camera::GetModelViewMatrix(Matrix4x4 &mat) { mat = mViewOrientation; Vector3 pos = mViewOrientation * -mPosition; mat.x[3][0] = pos.x; mat.x[3][1] = pos.y; mat.x[3][2] = pos.z; //glGetFloatv(GL_MODELVIEW_MATRIX, (float *)mat.x); } void Camera::CalcFrustum(Frustum &frustum) { // we grab the plane equations of the six clipplanes of the viewfrustum Matrix4x4 matViewing, matProjectionView; GetModelViewMatrix(matViewing); GetProjectionMatrix(matProjectionView); matProjectionView = matViewing * matProjectionView; float planes[6][4]; ////////// //-- extract the plane equations for (int i = 0; i < 4; ++ i) { planes[0][i] = matProjectionView.x[i][3] - matProjectionView.x[i][0]; // right plane planes[1][i] = matProjectionView.x[i][3] + matProjectionView.x[i][0]; // left plane planes[2][i] = matProjectionView.x[i][3] + matProjectionView.x[i][1]; // bottom plane planes[3][i] = matProjectionView.x[i][3] - matProjectionView.x[i][1]; // top plane planes[4][i] = matProjectionView.x[i][3] - matProjectionView.x[i][2]; // far plane planes[5][i] = matProjectionView.x[i][3] + matProjectionView.x[i][2]; // near plane } //////////// //-- normalize the coefficients for (int i = 0; i < 6; ++ i) { // the clipping planes look outward the frustum, // so distances > 0 mean that a point is outside float fInvLength = -1.0f / sqrt(planes[i][0] * planes[i][0] + planes[i][1] * planes[i][1] + planes[i][2] * planes[i][2]); planes[i][0] *= fInvLength; planes[i][1] *= fInvLength; planes[i][2] *= fInvLength; planes[i][3] *= fInvLength; frustum.mClipPlanes[i].mNormal = Vector3(planes[i][0], planes[i][1], planes[i][2]); frustum.mClipPlanes[i].mD = planes[i][3]; } } void Camera::Frustum::CalcNPVertexIndices(int *indices) { for (int i = 0; i < 6; ++ i) { // n-vertex indices[i * 2 + 0] = AxisAlignedBox3::GetIndexNearestVertex(mClipPlanes[i].mNormal); // p-vertex indices[i * 2 + 1] = AxisAlignedBox3::GetIndexFarthestVertex(mClipPlanes[i].mNormal); } } void Camera::SetupCameraView() { Matrix4x4 viewOrientation = mViewOrientation; Vector3 pos = mViewOrientation * -mPosition; viewOrientation.x[3][0] = pos.x; viewOrientation.x[3][1] = pos.y; viewOrientation.x[3][2] = pos.z; glLoadMatrixf((float *)viewOrientation.x); } void Camera::ComputePoints(Vector3 &ftl, Vector3 &ftr, Vector3 &fbl, Vector3 &fbr, Vector3 &ntl, Vector3 &ntr, Vector3 &nbl, Vector3 &nbr) { float z_near = mNear; float z_far = mFar; float fov = mFovy; const float w_near = 2.0f * tan(fov * 0.5f) * z_near; const float h_near = w_near / GetAspect(); const float w_far = 2.0f * tan(fov * 0.5f) * z_far; const float h_far = w_far / GetAspect(); const Vector3 view = GetDirection(); const Vector3 fc = mPosition + view * z_far; const Vector3 up = GetUpVector(); const Vector3 right = GetRightVector(); Vector3 t1, t2; t1 = h_far * 0.5f * up; t2 = w_far * 0.5f * right; ftl = fc + t1 - t2; ftr = fc + t1 + t2; fbl = fc - t1 - t2; fbr = fc - t1 + t2; const Vector3 nc = mPosition + view * z_near; t1 = h_near * 0.5f * up; t2 = w_near * 0.5f * right; ntl = nc + t1 - t2; ntr = nc + t1 + t2; nbl = nc - t1 - t2; nbr = nc - t1 + t2; } void Camera::SetOrtho(bool ortho) { mIsOrtho = true; } void Camera::Yaw(float angle) { mYaw += angle; CalculateFromPitchAndYaw(); } void Camera::Pitch(float angle) { mPitch += angle; CalculateFromPitchAndYaw(); } void Camera::SetDirection(const Vector3 &dir) { Vector3 ndir = -Normalize(dir); //mPitch = atan2(dir.x, dir.z); //mYaw = atan2(dir.y, sqrt((dir.x * dir.x) + (dir.z * dir.z))); //mPitch = atan2(dir.x, dir.y); mPitch = -atan2(ndir.x, ndir.y); mYaw = atan2(ndir.z, sqrt((ndir.x * ndir.x) + (ndir.y * ndir.y))); CalculateFromPitchAndYaw(); } void Camera::CalculateFromPitchAndYaw() { mViewOrientation = mBaseOrientation; Matrix4x4 roty = RotationYMatrix(mPitch); Matrix4x4 rotx = RotationXMatrix(mYaw); mViewOrientation *= roty; mViewOrientation *= rotx; } Vector3 Camera::GetDirection() const { return -Vector3(mViewOrientation.x[0][2], mViewOrientation.x[1][2], mViewOrientation.x[2][2]); } Vector3 Camera::GetUpVector() const { return Vector3(mViewOrientation.x[0][1], mViewOrientation.x[1][1], mViewOrientation.x[2][1]); } Vector3 Camera::GetRightVector() const { return Vector3(mViewOrientation.x[0][0], mViewOrientation.x[1][0], mViewOrientation.x[2][0]); } }