-
Notifications
You must be signed in to change notification settings - Fork 3
/
Camera.hpp
235 lines (213 loc) · 8.52 KB
/
Camera.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/**
* @file Camera.hpp
* @brief Abstract Camera class to be placed (position and orientation) within our scene.
* @author Dr. Jeffrey Paone
*
* @copyright MIT License Copyright (c) 2021 Dr. Jeffrey Paone
*
* These functions, classes, and constants help minimize common
* code that needs to be written.
*
* @warning This header file depends upon GLAD (or alternatively GLEW)
* @warning This header file depends upon glm
*/
#ifndef CSCI441_CAMERA_HPP
#define CSCI441_CAMERA_HPP
#ifdef CSCI441_USE_GLEW
#include <GL/glew.h>
#else
#include <glad/gl.h>
#endif
#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp>
#include <glm/gtc/constants.hpp>
#include <glm/gtc/matrix_transform.hpp>
namespace CSCI441 {
/**
* @brief Abstract Class to represent a synthetic camera. The following methods must be overridden:<br>
* - recomputeOrientation()<br>
* - moveForward()<br>
* - moveBackward()
*/
class Camera {
public:
/**
* @brief properly destroy concrete children
*/
virtual ~Camera() = default;
/**
* @brief Uses theta, phi, & radius to update the
* camera's view matrix parameters. The camera orientation
* is controlled via spherical coordinates and this method
* would orient and/or position the camera in cartesian
* coordinates.
*/
virtual void recomputeOrientation() = 0;
/**
* @brief steps forward along the camera's view
* @param movementFactor scaling factor for distance to move
*/
[[maybe_unused]] virtual void moveForward(GLfloat movementFactor) = 0;
/**
* @brief steps backward along the camera's view
* @param movementFactor scaling factor for distance to move
*/
[[maybe_unused]] virtual void moveBackward(GLfloat movementFactor) = 0;
/**
* @brief rotates the camera's POV by adding to theta & phi then ensuring
* phi stays within the (0, pi) range and finally calls through to
* recomputeOrientation() to update the view parameters after the rotation
* @param dTheta change in rotation of theta represented in radians
* @param dPhi change in rotation of phi represented in radians
* @note There is a default implementation to update theta & phi, but the
* method is overridable in the event a camera should be fixed and rotation
* can then be disabled.
*/
[[maybe_unused]] [[maybe_unused]] virtual void rotate(GLfloat dTheta, GLfloat dPhi);
/**
* @brief creates the View Matrix based on the position, lookAt point, and up vector
*/
virtual void computeViewMatrix() final { mViewMatrix = glm::lookAt(mCameraPosition, mCameraLookAtPoint, mCameraUpVector ); }
/**
* @brief returns the current projection matrix for the associated camera
* @returns homogeneous projection matrix
*/
[[maybe_unused]] [[nodiscard]] virtual glm::mat4 getProjectionMatrix() const final { return mProjectionMatrix; }
/**
* @brief returns the current view matrix for the associated camera
* @returns homogeneous view matrix
*/
[[maybe_unused]] [[nodiscard]] virtual glm::mat4 getViewMatrix() const final { return mViewMatrix; }
/**
* @brief returns the current camera position in world space
* @returns homogeneous world space point
*/
[[nodiscard]] virtual glm::vec3 getPosition() const final { return mCameraPosition; }
/**
* @brief returns the current lookAt point in world space
* @returns homogeneous world space point
*/
[[nodiscard]] virtual glm::vec3 getLookAtPoint() const final { return mCameraLookAtPoint; }
/**
* @brief returns the current up vector in world space
* @returns homogeneous world space vector
*/
[[nodiscard]] virtual glm::vec3 getUpVector() const final { return mCameraUpVector; }
/**
* @brief returns the current theta value in radians
* @returns spherical theta coordinate
*/
[[nodiscard]] virtual GLfloat getTheta() const final { return mCameraTheta; }
/**
* @brief returns the current phi value in radians
* @returns spherical phi coordinate
*/
[[nodiscard]] virtual GLfloat getPhi() const final { return mCameraPhi; }
/**
* @brief returns the current radius in world space
* @returns spherical radius coordinate
*/
[[maybe_unused]] [[nodiscard]] GLfloat getRadius() const { return mCameraRadius; }
/**
* @brief sets the camera's position in world space
* @param pos the new camera world space position
*/
virtual void setPosition( const glm::vec3 pos ) final { mCameraPosition = pos; }
/**
* @brief sets the camera's lookAt point in world space
* @param lookAt the new camera world space lookAt point
*/
virtual void setLookAtPoint( const glm::vec3 lookAt ) final { mCameraLookAtPoint = lookAt; }
/**
* @brief sets the camera's up vector in world space
* @param up the new camera world space up vector
*/
virtual void setUpVector( const glm::vec3 up ) final { mCameraUpVector = up; }
/**
* @brief sets the camera's theta angle in radians
* @param t the new camera theta angle in radians
*/
virtual void setTheta( const GLfloat t ) final { mCameraTheta = t; }
/**
* @brief sets the camera's phi angle in radians
* @param p the new camera phi angle in radians
*/
virtual void setPhi( const GLfloat p ) final { mCameraPhi = p; }
/**
* @brief sets the camera's radius in world space
* @param r the new camera radius in world space
*/
virtual void setRadius( const GLfloat r ) final { mCameraRadius = r; }
protected:
/**
* @brief create a default camera at the origin, looking down the
* negative Z axis oriented with the world coordinate system
*/
Camera();
/**
* @brief stores the Projection Matrix
*/
glm::mat4 mProjectionMatrix;
/**
* @brief stores the View Matrix corresponding to the inverse of the Camera's Matrix
*/
glm::mat4 mViewMatrix;
/**
* @brief the cartesian position in world space of the camera
*/
glm::vec3 mCameraPosition;
/**
* @brief the cartesian direction the camera is facing in world space
*/
glm::vec3 mCameraDirection;
/**
* @brief the world space point in front of the camera
*/
glm::vec3 mCameraLookAtPoint;
/**
* @brief the up vector of the camera specified in world space
*/
glm::vec3 mCameraUpVector;
/**
* @brief spherical angle for yaw direction in radians
*/
GLfloat mCameraTheta;
/**
* @brief spherical angle for pitch direction in radians
*/
GLfloat mCameraPhi;
/**
* @brief spherical magnitude for direction in world space
*/
GLfloat mCameraRadius;
private:
/**
* @brief keeps phi within the range (0, pi) to prevent the camera from flipping upside down
* @note to invert camera - alter the up vector to flip/rotate camera orientation
*/
void _clampCameraPhi();
};
}
inline CSCI441::Camera::Camera() :
mProjectionMatrix( glm::mat4(1.0f) ),
mViewMatrix( glm::mat4(1.0f) ),
mCameraPosition( glm::vec3(0.0f, 0.0f, 0.0f ) ),
mCameraDirection( glm::vec3(0.0f, 0.0f, -1.0f ) ),
mCameraLookAtPoint( glm::vec3(0.0f, 0.0f, -1.0f ) ),
mCameraUpVector( glm::vec3(0.0f, 1.0f, 0.0f ) ),
mCameraTheta( 0.0f ),
mCameraPhi( glm::pi<float>() / 2.0f ),
mCameraRadius( 1.0f ) {
}
[[maybe_unused]]
inline void CSCI441::Camera::rotate(const GLfloat dTheta, const GLfloat dPhi) {
mCameraTheta += dTheta; // update theta
mCameraPhi += dPhi; // update phi
_clampCameraPhi(); // bounds check phi
recomputeOrientation(); // convert to cartesian
}
inline void CSCI441::Camera::_clampCameraPhi() {
if(mCameraPhi <= 0.0f) mCameraPhi = 0.0f + 0.001f;
if(mCameraPhi >= glm::pi<float>()) mCameraPhi = glm::pi<float>() - 0.001f;
}
#endif // CSCI441_CAMERA_HPP