Set up CCamera, CLight, and CSceneNode to use mutable members for caching; modified CSceneNode to allow subclasses to change how transform is calculated

This commit is contained in:
parax0
2015-12-06 21:23:52 -07:00
parent c260e547c9
commit 0da183b161
14 changed files with 291 additions and 234 deletions

View File

@@ -13,36 +13,36 @@ CCamera::CCamera()
mYaw = -Math::skHalfPi;
mPitch = 0.0f;
SetOrbit(CVector3f(0), 5.f);
Update();
mMoveSpeed = 1.f;
mLookSpeed = 1.f;
mViewOutdated = true;
mProjectionOutdated = true;
mFrustumPlanesOutdated = true;
mTransformDirty = true;
mViewDirty = true;
mProjectionDirty = true;
mFrustumPlanesDirty = true;
}
CCamera::CCamera(CVector3f Position, CVector3f /*Target*/)
{
// todo: make it actually look at the target!
// don't actually use this constructor, it's unfinished and won't work properly
mMode = eFreeCamera;
mMoveSpeed = 1.f;
mLookSpeed = 1.f;
mPosition = Position;
mYaw = -Math::skHalfPi;
mPitch = 0.0f;
Update();
}
void CCamera::Pan(float XAmount, float YAmount)
{
if (mMode == eFreeCamera)
{
Update();
mPosition += mRightVector * (XAmount * mMoveSpeed);
mPosition += mUpVector * (YAmount * mMoveSpeed);
mViewOutdated = true;
mFrustumPlanesOutdated = true;
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
else
@@ -53,24 +53,26 @@ void CCamera::Rotate(float XAmount, float YAmount)
{
mYaw -= (XAmount * mLookSpeed * 0.3f);
mPitch -= (YAmount * mLookSpeed * 0.3f);
ValidatePitch();
mViewOutdated = true;
mFrustumPlanesOutdated = true;
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
void CCamera::Zoom(float Amount)
{
if (mMode == eFreeCamera)
{
Update();
mPosition += mDirection * (Amount * mMoveSpeed);
}
else
{
mOrbitDistance -= Amount * mMoveSpeed;
mTransformDirty = true;
}
mViewOutdated = true;
mFrustumPlanesOutdated = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
void CCamera::Snap(CVector3f Position)
@@ -78,9 +80,9 @@ void CCamera::Snap(CVector3f Position)
mPosition = Position;
mYaw = -Math::skHalfPi;
mPitch = 0.0f;
mViewOutdated = true;
mFrustumPlanesOutdated = true;
Update();
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
void CCamera::ProcessKeyInput(EKeyInputs KeyFlags, double DeltaTime)
@@ -117,7 +119,7 @@ void CCamera::ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, fl
}
}
CRay CCamera::CastRay(CVector2f DeviceCoords)
CRay CCamera::CastRay(CVector2f DeviceCoords) const
{
CMatrix4f InverseVP = (ViewMatrix().Transpose() * ProjectionMatrix().Transpose()).Inverse();
@@ -134,8 +136,11 @@ CRay CCamera::CastRay(CVector2f DeviceCoords)
void CCamera::SetMoveMode(ECameraMoveMode Mode)
{
mMode = Mode;
mViewOutdated = true;
mFrustumPlanesOutdated = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
if (mMode == eOrbitCamera)
mTransformDirty = true;
}
void CCamera::SetOrbit(const CVector3f& OrbitTarget, float Distance)
@@ -145,24 +150,34 @@ void CCamera::SetOrbit(const CVector3f& OrbitTarget, float Distance)
if (mMode == eOrbitCamera)
{
mViewOutdated = true;
mFrustumPlanesOutdated = true;
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
}
void CCamera::SetOrbit(const CAABox& OrbitTarget, float DistScale /*= 2.5f*/)
void CCamera::SetOrbit(const CAABox& OrbitTarget, float DistScale /*= 4.f*/)
{
CVector3f Min = OrbitTarget.Min();
CVector3f Max = OrbitTarget.Max();
mOrbitTarget = OrbitTarget.Center();
mOrbitDistance = ((Max.x - Min.x) + (Max.y - Min.y) + (Max.z - Min.z)) / 3.f;
mOrbitDistance *= DistScale;
// Find largest extent
CVector3f Extent = (Max - Min) / 2.f;
float Dist = 0.f;
if (Extent.x >= Extent.y && Extent.x >= Extent.z) Dist = Extent.x;
else if (Extent.y >= Extent.x && Extent.y >= Extent.z) Dist = Extent.y;
else Dist = Extent.z;
mOrbitDistance = Dist * DistScale;
if (mMode == eOrbitCamera)
{
mViewOutdated = true;
mFrustumPlanesOutdated = true;
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
}
@@ -172,12 +187,13 @@ void CCamera::SetOrbitDistance(float Distance)
if (mMode == eOrbitCamera)
{
mViewOutdated = true;
mFrustumPlanesOutdated = true;
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
}
void CCamera::LoadMatrices()
void CCamera::LoadMatrices() const
{
CGraphics::sMVPBlock.ViewMatrix = ViewMatrix();
CGraphics::sMVPBlock.ProjectionMatrix = ProjectionMatrix();
@@ -187,21 +203,25 @@ void CCamera::LoadMatrices()
// ************ GETTERS ************
CVector3f CCamera::Position() const
{
UpdateTransform();
return mPosition;
}
CVector3f CCamera::Direction() const
{
UpdateTransform();
return mDirection;
}
CVector3f CCamera::UpVector() const
{
UpdateTransform();
return mUpVector;
}
CVector3f CCamera::RightVector() const
{
UpdateTransform();
return mRightVector;
}
@@ -225,53 +245,36 @@ ECameraMoveMode CCamera::MoveMode() const
return mMode;
}
const CMatrix4f& CCamera::ViewMatrix()
const CMatrix4f& CCamera::ViewMatrix() const
{
if (mViewOutdated)
UpdateView();
return mCachedViewMatrix;
UpdateView();
return mViewMatrix;
}
const CMatrix4f& CCamera::ProjectionMatrix()
const CMatrix4f& CCamera::ProjectionMatrix() const
{
if (mProjectionOutdated)
UpdateProjection();
return mCachedProjectionMatrix;
UpdateProjection();
return mProjectionMatrix;
}
const CFrustumPlanes& CCamera::FrustumPlanes()
const CFrustumPlanes& CCamera::FrustumPlanes() const
{
if (mFrustumPlanesOutdated)
UpdateFrustum();
return mCachedFrustumPlanes;
UpdateFrustum();
return mFrustumPlanes;
}
// ************ SETTERS ************
void CCamera::SetPosition(CVector3f Position)
{
mPosition = Position;
mViewOutdated = true;
mFrustumPlanesOutdated = true;
}
void CCamera::SetDirection(CVector3f Direction)
{
mDirection = Direction;
mViewOutdated = true;
mFrustumPlanesOutdated = true;
}
void CCamera::SetYaw(float Yaw)
{
mYaw = Yaw;
mTransformDirty = true;
}
void CCamera::SetPitch(float Pitch)
{
mPitch = Pitch;
ValidatePitch();
mTransformDirty = true;
}
void CCamera::SetMoveSpeed(float MoveSpeed)
@@ -287,62 +290,81 @@ void CCamera::SetLookSpeed(float LookSpeed)
void CCamera::SetAspectRatio(float AspectRatio)
{
mAspectRatio = AspectRatio;
mProjectionOutdated = true;
mFrustumPlanesOutdated = true;
mProjectionDirty = true;
mFrustumPlanesDirty = true;
}
// ************ PRIVATE ************
void CCamera::Update()
void CCamera::ValidatePitch()
{
// Update direction
// This function mainly just exists to ensure the camera doesn't flip upside down
if (mPitch > Math::skHalfPi) mPitch = Math::skHalfPi;
if (mPitch < -Math::skHalfPi) mPitch = -Math::skHalfPi;
mDirection = CVector3f(
cos(mPitch) * cos(mYaw),
cos(mPitch) * sin(mYaw),
sin(mPitch)
);
mRightVector = CVector3f(
cos(mYaw - Math::skHalfPi),
sin(mYaw - Math::skHalfPi),
0
);
mUpVector = mRightVector.Cross(mDirection);
// Update position
if (mMode == eOrbitCamera)
{
if (mOrbitDistance < 1.f) mOrbitDistance = 1.f;
mPosition = mOrbitTarget + (mDirection * -mOrbitDistance);
}
mViewOutdated = true;
mFrustumPlanesOutdated = true;
}
void CCamera::UpdateView()
void CCamera::UpdateTransform() const
{
// Transform should be marked dirty when pitch, yaw, or orbit target/distance are changed
if (mTransformDirty)
{
mDirection = CVector3f(
cos(mPitch) * cos(mYaw),
cos(mPitch) * sin(mYaw),
sin(mPitch)
);
mRightVector = CVector3f(
cos(mYaw - Math::skHalfPi),
sin(mYaw - Math::skHalfPi),
0
);
mUpVector = mRightVector.Cross(mDirection);
// Update position
if (mMode == eOrbitCamera)
{
if (mOrbitDistance < 1.f) mOrbitDistance = 1.f;
mPosition = mOrbitTarget + (mDirection * -mOrbitDistance);
}
mViewDirty = true;
mFrustumPlanesDirty = true;
mTransformDirty = false;
}
}
void CCamera::UpdateView() const
{
// todo: don't use glm
Update();
UpdateTransform();
glm::vec3 glmpos(mPosition.x, mPosition.y, mPosition.z);
glm::vec3 glmdir(mDirection.x, mDirection.y, mDirection.z);
glm::vec3 glmup(mUpVector.x, mUpVector.y, mUpVector.z);
mCachedViewMatrix = CMatrix4f::FromGlmMat4(glm::lookAt(glmpos, glmpos + glmdir, glmup)).Transpose();
mViewOutdated = false;
if (mViewDirty)
{
glm::vec3 glmpos(mPosition.x, mPosition.y, mPosition.z);
glm::vec3 glmdir(mDirection.x, mDirection.y, mDirection.z);
glm::vec3 glmup(mUpVector.x, mUpVector.y, mUpVector.z);
mViewMatrix = CMatrix4f::FromGlmMat4(glm::lookAt(glmpos, glmpos + glmdir, glmup)).Transpose();
mViewDirty = false;
}
}
void CCamera::UpdateProjection()
void CCamera::UpdateProjection() const
{
mCachedProjectionMatrix = Math::PerspectiveMatrix(55.f, mAspectRatio, 0.1f, 4096.f);
mProjectionOutdated = false;
if (mProjectionDirty)
{
mProjectionMatrix = Math::PerspectiveMatrix(55.f, mAspectRatio, 0.1f, 4096.f);
mProjectionDirty = false;
}
}
void CCamera::UpdateFrustum()
void CCamera::UpdateFrustum() const
{
mCachedFrustumPlanes.SetPlanes(mPosition, mDirection, 55.f, mAspectRatio, 0.1f, 4096.f);
mFrustumPlanesOutdated = false;
UpdateTransform();
if (mFrustumPlanesDirty)
{
mFrustumPlanes.SetPlanes(mPosition, mDirection, 55.f, mAspectRatio, 0.1f, 4096.f);
mFrustumPlanesDirty = false;
}
}

View File

@@ -16,28 +16,38 @@ enum ECameraMoveMode
eFreeCamera, eOrbitCamera
};
/* This class uses a lot of mutable members as an optimization so that they can
* be updated as infrequently as possible (eg only when the values are requested
* the next time after changes are made) while still always returning the correct
* value via the const get functions. They are not modified in const functions
* beyond ensuring that all data is valid and synced with everything else (eg
* mPosition is only modified to ensure it's correct in orbit mode given the
* target/distance/pitch/yaw; it won't be modified as a camera snap in a const
* function). */
class CCamera
{
ECameraMoveMode mMode;
CVector3f mPosition;
CVector3f mDirection;
CVector3f mRightVector;
CVector3f mUpVector;
mutable CVector3f mPosition;
mutable CVector3f mDirection;
mutable CVector3f mRightVector;
mutable CVector3f mUpVector;
float mAspectRatio;
float mYaw;
float mPitch;
CVector3f mOrbitTarget;
float mOrbitDistance;
mutable float mOrbitDistance;
float mMoveSpeed;
float mLookSpeed;
CMatrix4f mCachedViewMatrix;
CMatrix4f mCachedProjectionMatrix;
CFrustumPlanes mCachedFrustumPlanes;
bool mViewOutdated;
bool mProjectionOutdated;
bool mFrustumPlanesOutdated;
mutable CMatrix4f mViewMatrix;
mutable CMatrix4f mProjectionMatrix;
mutable CFrustumPlanes mFrustumPlanes;
mutable bool mTransformDirty;
mutable bool mViewDirty;
mutable bool mProjectionDirty;
mutable bool mFrustumPlanesDirty;
public:
CCamera();
@@ -49,12 +59,12 @@ public:
void Snap(CVector3f Position);
void ProcessKeyInput(EKeyInputs KeyFlags, double DeltaTime);
void ProcessMouseInput(EKeyInputs KeyFlags, EMouseInputs MouseFlags, float XMovement, float YMovement);
CRay CastRay(CVector2f DeviceCoords);
void LoadMatrices();
CRay CastRay(CVector2f DeviceCoords) const;
void LoadMatrices() const;
void SetMoveMode(ECameraMoveMode Mode);
void SetOrbit(const CVector3f& OrbitTarget, float Distance);
void SetOrbit(const CAABox& OrbitTarget, float DistScale = 2.5f);
void SetOrbit(const CAABox& OrbitTarget, float DistScale = 4.f);
void SetOrbitDistance(float Distance);
// Getters
@@ -66,13 +76,11 @@ public:
float Pitch() const;
float FieldOfView() const;
ECameraMoveMode MoveMode() const;
const CMatrix4f& ViewMatrix();
const CMatrix4f& ProjectionMatrix();
const CFrustumPlanes& FrustumPlanes();
const CMatrix4f& ViewMatrix() const;
const CMatrix4f& ProjectionMatrix() const;
const CFrustumPlanes& FrustumPlanes() const;
// Setters
void SetPosition(CVector3f Position);
void SetDirection(CVector3f Direction);
void SetYaw(float Yaw);
void SetPitch(float Pitch);
void SetMoveSpeed(float MoveSpeed);
@@ -81,10 +89,11 @@ public:
// Private
private:
void Update();
void UpdateView();
void UpdateProjection();
void UpdateFrustum();
void ValidatePitch();
void UpdateTransform() const;
void UpdateView() const;
void UpdateProjection() const;
void UpdateFrustum() const;
};
#endif // CCAMERA_H