#ifndef Camera_h__ #define Camera_h__ #include "IGraphicsNode.h" #include "math/LifeMath.h" #include "camera/Frustum.h" namespace LifeGraphics { class Camera : public IGraphicsNode { private: bool isViewValid; bool isProjValid; float fov; float nearPlane; float farPlane; float viewAspect; LifeMath::float3 right; LifeMath::float3 eye; LifeMath::float3 at; LifeMath::float3 up; float yaw, pitch, roll; Frustum frustum; LifeMath::float3 ViewDirection; LifeMath::float4x4 viewMatrix; LifeMath::float4x4 projectionMatrix; bool freeCam; LifeMath::float3 fDir; NodeType getType() { return NT_CAMERA; } void UpdatePerspectiveMatrix() { Mat4x4PerspectiveFOV(fov, viewAspect, nearPlane, farPlane, projectionMatrix); isProjValid = true; frustum.UpdateFrustum(viewMatrix * projectionMatrix); } void ComputeView() { //g_viewMatrix = Matrix4x4.LookAtLH(g_eye, g_at, g_up); ViewDirection = at - eye; LifeMath::Vec3Normalize(&ViewDirection, &ViewDirection); up = LifeMath::float3(0,1,0); //fixup UP vector if(LifeMath::Vec3Dot(&ViewDirection, &up) > 0.998f) { up = LifeMath::float3(0,0,-1); } else if(LifeMath::Vec3Dot(&ViewDirection, &up) < -0.998f) { up = LifeMath::float3(0,0,1); } //orthoganalize right vector LifeMath::Vec3Cross(up, ViewDirection, right); LifeMath::Vec3Normalize(&right); //orthoganalize up vector LifeMath::Vec3Cross(ViewDirection, right, up); LifeMath::Vec3Normalize(&up); //compute view matrix float x = -LifeMath::Vec3Dot(&right, &eye); float y = -LifeMath::Vec3Dot(&up, &eye); float z = -LifeMath::Vec3Dot(&ViewDirection, &eye); viewMatrix.M11 = right.X; viewMatrix.M12 = up.X; viewMatrix.M13 = ViewDirection.X; viewMatrix.M14 = 0; viewMatrix.M21 = right.Y; viewMatrix.M22 = up.Y; viewMatrix.M23 = ViewDirection.Y; viewMatrix.M24 = 0; viewMatrix.M31 = right.Z; viewMatrix.M32 = up.Z; viewMatrix.M33 = ViewDirection.Z; viewMatrix.M34 = 0; viewMatrix.M41 = x; viewMatrix.M42 = y; viewMatrix.M43 = z; viewMatrix.M44 = 1.0f; isViewValid = true; frustum.UpdateFrustum(viewMatrix * projectionMatrix); } public: Camera(); ~Camera(); void update(float dt) { } void setAspect(float aspect) { viewAspect = aspect; isProjValid = false; } void setFov(float _fov) { fov = _fov; isProjValid = false; } void setNear(float val) { nearPlane = val; isProjValid = false; } void setFar(float val) { farPlane = val; isProjValid = false; } float getNear() const { return nearPlane; } float getFar() const { return farPlane; } LifeMath::float4x4 getView() { if(isViewValid) { return viewMatrix; } else { ComputeView(); isViewValid = true; return viewMatrix; } } LifeMath::float4x4 getProj() { if(isProjValid) { return projectionMatrix; } else { UpdatePerspectiveMatrix(); isProjValid = true; return projectionMatrix; } } LifeMath::float3 getDirection() { return ViewDirection; } LifeMath::float3 getRight() { return right; } void setPosition(float x, float y, float z) { eye = LifeMath::float3(x, y, z); isViewValid = false; } void setPosition(const LifeMath::float3& position) { eye = position; isViewValid = false; //ComputeView(); /*isViewValid = false;*/ } void setDirection(LifeMath::float3& direction) { at = direction; //at = direction - eye; //LifeMath::Vec3Normalize(&at); up.X = 0.0f; up.Y = 1.0f; up.Z = 0.0f; isViewValid = false; //LifeMath::Vec3Cross(up, at, right); //ComputeView(); } Frustum* getFrustum() { bool updateFrustum = false; if(!isViewValid) { ComputeView(); updateFrustum = true; } if(!isProjValid) { UpdatePerspectiveMatrix(); updateFrustum = true; } return &frustum; } const LifeMath::float3& getPosition() const { return eye; } float getFov() const { return fov; } float getAspect() const { return viewAspect; } const LifeMath::float3& getUp() const { return up; } void Yaw(float angle) { yaw += angle; LifeMath::float3 axis = LifeMath::float3(0.0f, 1.0f, 0.0f); LifeMath::float4x4 r; Mat4x4RotationAxis(&axis, angle, &r); if (freeCam) { Vec3TransformCoordinate(right, r, right); Vec3TransformCoordinate(at, r, at); } else { Vec3TransformCoordinate(fDir, r, fDir); Vec3TransformCoordinate(right, r, right); } isViewValid = false; } void Pitch(float angle) { pitch += angle; LifeMath::float4x4 r; Mat4x4RotationAxis(&right, angle, &r); if (freeCam) { Vec3TransformCoordinate(up, r, up); Vec3TransformCoordinate(at, r, at); } else { Vec3TransformCoordinate(up, r, up); Vec3TransformCoordinate(fDir, r, fDir); } isViewValid = false; } void Roll(float angle) { roll += angle; LifeMath::float4x4 r; Mat4x4RotationAxis(&at, angle, &r); Vec3TransformCoordinate(up, r, up); Vec3TransformCoordinate(right, r, at); isViewValid = false; } void GetCorners(LifeMath::float3* corners) { if(!isViewValid) ComputeView(); if(!isProjValid) UpdatePerspectiveMatrix(); LifeMath::float4x4 vp = viewMatrix * projectionMatrix; Mat4x4Invert(&vp); for (int i = 0; i < 8; i++) { corners[i] = Vec3TransformCoordinate(vp, baseCorners[i]); } } void SetupBasis(const LifeMath::float3& _pos, const LifeMath::float3& _front, const LifeMath::float3& _top, const LifeMath::float3& _right) { eye = _pos; right = _right; up = _top; at = _front; ViewDirection = at; LifeMath::Vec3Normalize(&right); LifeMath::Vec3Normalize(&at); LifeMath::Vec3Normalize(&up); //compute view matrix float x = -LifeMath::Vec3Dot(&right, &eye); float y = -LifeMath::Vec3Dot(&up, &eye); float z = -LifeMath::Vec3Dot(&at, &eye); viewMatrix.M11 = right.X; viewMatrix.M12 = up.X; viewMatrix.M13 = at.X; viewMatrix.M14 = 0.0f; viewMatrix.M21 = right.Y; viewMatrix.M22 = up.Y; viewMatrix.M23 = at.Y; viewMatrix.M24 = 0.0f; viewMatrix.M31 = right.Z; viewMatrix.M32 = up.Z; viewMatrix.M33 = at.Z; viewMatrix.M34 = 0.0f; viewMatrix.M41 = x; viewMatrix.M42 = y; viewMatrix.M43 = z; viewMatrix.M44 = 1.0f; isViewValid = true; } }; } #endif // Camera_h__