|
| 1 | +// |
| 2 | +// Copyright (c) Microsoft. All rights reserved. |
| 3 | +// This code is licensed under the MIT License (MIT). |
| 4 | +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF |
| 5 | +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY |
| 6 | +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR |
| 7 | +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. |
| 8 | +// |
| 9 | +// Developed by Minigraph |
| 10 | +// |
| 11 | +// Author: James Stanard |
| 12 | +// |
| 13 | + |
| 14 | +#pragma once |
| 15 | + |
| 16 | +#include "VectorMath.h" |
| 17 | +#include "Math/Frustum.h" |
| 18 | + |
| 19 | +namespace Math |
| 20 | +{ |
| 21 | + class BaseCamera |
| 22 | + { |
| 23 | + public: |
| 24 | + |
| 25 | + // Call this function once per frame and after you've changed any state. This |
| 26 | + // regenerates all matrices. Calling it more or less than once per frame will break |
| 27 | + // temporal effects and cause unpredictable results. |
| 28 | + void Update(); |
| 29 | + |
| 30 | + // Public functions for controlling where the camera is and its orientation |
| 31 | + void SetEyeAtUp( Vector3 eye, Vector3 at, Vector3 up ); |
| 32 | + void SetLookDirection( Vector3 forward, Vector3 up ); |
| 33 | + void SetRotation( Quaternion basisRotation ); |
| 34 | + void SetPosition( Vector3 worldPos ); |
| 35 | + void SetTransform( const AffineTransform& xform ); |
| 36 | + void SetTransform( const OrthogonalTransform& xform ); |
| 37 | + |
| 38 | + const Quaternion GetRotation() const { return m_CameraToWorld.GetRotation(); } |
| 39 | + const Vector3 GetRightVec() const { return m_Basis.GetX(); } |
| 40 | + const Vector3 GetUpVec() const { return m_Basis.GetY(); } |
| 41 | + const Vector3 GetForwardVec() const { return -m_Basis.GetZ(); } |
| 42 | + const Vector3 GetPosition() const { return m_CameraToWorld.GetTranslation(); } |
| 43 | + |
| 44 | + // Accessors for reading the various matrices and frusta |
| 45 | + const Matrix4& GetViewMatrix() const { return m_ViewMatrix; } |
| 46 | + const Matrix4& GetProjMatrix() const { return m_ProjMatrix; } |
| 47 | + const Matrix4& GetViewProjMatrix() const { return m_ViewProjMatrix; } |
| 48 | + const Matrix4& GetReprojectionMatrix() const { return m_ReprojectMatrix; } |
| 49 | + const Frustum& GetViewSpaceFrustum() const { return m_FrustumVS; } |
| 50 | + const Frustum& GetWorldSpaceFrustum() const { return m_FrustumWS; } |
| 51 | + |
| 52 | + protected: |
| 53 | + |
| 54 | + BaseCamera() : m_CameraToWorld(kIdentity), m_Basis(kIdentity) {} |
| 55 | + |
| 56 | + void SetProjMatrix( const Matrix4& ProjMat ) { m_ProjMatrix = ProjMat; } |
| 57 | + |
| 58 | + OrthogonalTransform m_CameraToWorld; |
| 59 | + |
| 60 | + // Redundant data cached for faster lookups. |
| 61 | + Matrix3 m_Basis; |
| 62 | + |
| 63 | + // Transforms homogeneous coordinates from world space to view space. In this case, view space is defined as +X is |
| 64 | + // to the right, +Y is up, and -Z is forward. This has to match what the projection matrix expects, but you might |
| 65 | + // also need to know what the convention is if you work in view space in a shader. |
| 66 | + Matrix4 m_ViewMatrix; // i.e. "World-to-View" matrix |
| 67 | + |
| 68 | + // The projection matrix transforms view space to clip space. Once division by W has occurred, the final coordinates |
| 69 | + // can be transformed by the viewport matrix to screen space. The projection matrix is determined by the screen aspect |
| 70 | + // and camera field of view. A projection matrix can also be orthographic. In that case, field of view would be defined |
| 71 | + // in linear units, not angles. |
| 72 | + Matrix4 m_ProjMatrix; // i.e. "View-to-Projection" matrix |
| 73 | + |
| 74 | + // A concatenation of the view and projection matrices. |
| 75 | + Matrix4 m_ViewProjMatrix; // i.e. "World-To-Projection" matrix. |
| 76 | + |
| 77 | + // The view-projection matrix from the previous frame |
| 78 | + Matrix4 m_PreviousViewProjMatrix; |
| 79 | + |
| 80 | + // Projects a clip-space coordinate to the previous frame (useful for temporal effects). |
| 81 | + Matrix4 m_ReprojectMatrix; |
| 82 | + |
| 83 | + Frustum m_FrustumVS; // View-space view frustum |
| 84 | + Frustum m_FrustumWS; // World-space view frustum |
| 85 | + |
| 86 | + }; |
| 87 | + |
| 88 | + class Camera : public BaseCamera |
| 89 | + { |
| 90 | + public: |
| 91 | + Camera(); |
| 92 | + |
| 93 | + // Controls the view-to-projection matrix |
| 94 | + void SetPerspectiveMatrix( float verticalFovRadians, float aspectHeightOverWidth, float nearZClip, float farZClip ); |
| 95 | + void SetFOV( float verticalFovInRadians ) { m_VerticalFOV = verticalFovInRadians; UpdateProjMatrix(); } |
| 96 | + void SetAspectRatio( float heightOverWidth ) { m_AspectRatio = heightOverWidth; UpdateProjMatrix(); } |
| 97 | + void SetZRange( float nearZ, float farZ) { m_NearClip = nearZ; m_FarClip = farZ; UpdateProjMatrix(); } |
| 98 | + void ReverseZ( bool enable ) { m_ReverseZ = enable; UpdateProjMatrix(); } |
| 99 | + |
| 100 | + float GetFOV() const { return m_VerticalFOV; } |
| 101 | + float GetNearClip() const { return m_NearClip; } |
| 102 | + float GetFarClip() const { return m_FarClip; } |
| 103 | + float GetClearDepth() const { return m_ReverseZ ? 0.0f : 1.0f; } |
| 104 | + |
| 105 | + private: |
| 106 | + |
| 107 | + void UpdateProjMatrix( void ); |
| 108 | + |
| 109 | + float m_VerticalFOV; // Field of view angle in radians |
| 110 | + float m_AspectRatio; |
| 111 | + float m_NearClip; |
| 112 | + float m_FarClip; |
| 113 | + bool m_ReverseZ; // Invert near and far clip distances so that Z=0 is the far plane |
| 114 | + }; |
| 115 | + |
| 116 | + inline void BaseCamera::SetEyeAtUp( Vector3 eye, Vector3 at, Vector3 up ) |
| 117 | + { |
| 118 | + SetLookDirection(at - eye, up); |
| 119 | + SetPosition(eye); |
| 120 | + } |
| 121 | + |
| 122 | + inline void BaseCamera::SetPosition( Vector3 worldPos ) |
| 123 | + { |
| 124 | + m_CameraToWorld.SetTranslation( worldPos ); |
| 125 | + } |
| 126 | + |
| 127 | + inline void BaseCamera::SetTransform( const AffineTransform& xform ) |
| 128 | + { |
| 129 | + // By using these functions, we rederive an orthogonal transform. |
| 130 | + SetLookDirection(-xform.GetZ(), xform.GetY()); |
| 131 | + SetPosition(xform.GetTranslation()); |
| 132 | + } |
| 133 | + |
| 134 | + inline void BaseCamera::SetRotation( Quaternion basisRotation ) |
| 135 | + { |
| 136 | + m_CameraToWorld.SetRotation(Normalize(basisRotation)); |
| 137 | + m_Basis = Matrix3(m_CameraToWorld.GetRotation()); |
| 138 | + } |
| 139 | + |
| 140 | + inline Camera::Camera() : m_ReverseZ(true) |
| 141 | + { |
| 142 | + SetPerspectiveMatrix( XM_PIDIV4, 9.0f / 16.0f, 1.0f, 1000.0f ); |
| 143 | + } |
| 144 | + |
| 145 | + inline void Camera::SetPerspectiveMatrix( float verticalFovRadians, float aspectHeightOverWidth, float nearZClip, float farZClip ) |
| 146 | + { |
| 147 | + m_VerticalFOV = verticalFovRadians; |
| 148 | + m_AspectRatio = aspectHeightOverWidth; |
| 149 | + m_NearClip = nearZClip; |
| 150 | + m_FarClip = farZClip; |
| 151 | + |
| 152 | + UpdateProjMatrix(); |
| 153 | + |
| 154 | + m_PreviousViewProjMatrix = m_ViewProjMatrix; |
| 155 | + } |
| 156 | + |
| 157 | +} // namespace Math |
0 commit comments