Files
LifeProject/LifeGraphics/camera/Camera.h
T
2025-05-13 02:46:21 +03:00

329 lines
6.4 KiB
C++

#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__