-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcamera.h
212 lines (171 loc) · 7.42 KB
/
camera.h
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
#ifndef CAMERA_H
#define CAMERA_H
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/type_ptr.hpp"
#include "glm/gtx/quaternion.hpp"
#define GLM_ENABLE_EXPERIMENTAL
#include "glm/ext.hpp"
#include <vector>
// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
enum Camera_Movement {
FORWARD,
BACKWARD,
LEFT,
RIGHT
};
class Camera{
public:
Camera(glm::vec3 camPos, glm::vec3 up, glm::vec3 direction){
this->camPos = camPos;
worldUp = glm::vec3(0.0f, 1.0f, 0.0f);
this->up = glm::normalize(up);
this->direction = glm::normalize(direction);
speed = 2.5f;
sensitivity = 0.6f;
yaw = -90.0f;
pitch = 0.0f;
}
Camera(glm::vec3 camPos, glm::vec3 up, glm::vec3 direction, float speed, float sensitivity){
this->camPos = camPos;
worldUp = glm::vec3(0.0f, 1.0f, 0.0f);
this->up = glm::normalize(up);
this->direction = glm::normalize(direction);
this->speed = speed;
this->sensitivity = sensitivity;
yaw = -90.0f;
pitch = 0.0f;
}
void setPosition(float x, float y, float z){
camPos = glm::vec3(x, y, z);
}
void ProcessKeyboard(Camera_Movement move, float deltaTime){
//operations are opposite since direction points opposite to where the camera is facing
float cameraSpeed = static_cast<float>(speed * deltaTime);
if (move == FORWARD)
camPos -= cameraSpeed * direction; //want to decrease the direction since you are pointing in reverse direction
if (move == BACKWARD)
camPos += cameraSpeed * direction;
if (move == LEFT)
camPos -= glm::normalize(glm::cross(up, direction)) * cameraSpeed;
if (move == RIGHT)
camPos += glm::normalize(glm::cross(up, direction)) * cameraSpeed;
};
glm::mat4 worldToCamMatrix(){
// 1. Normalize direction
glm::vec3 newN = glm::normalize(direction);
// 2. Get positive right axis vector
glm::vec3 newU = glm::normalize(glm::cross(glm::normalize(worldUp), newN));
// 3. Calculate camera up vector
glm::vec3 newV = glm::cross(newN, newU);
// Create translation and rotation matrix
// In glm we access elements as mat[col][row] due to column-major layout
glm::mat4 translation = glm::mat4(1.0f); // Identity matrix by default
translation[3][0] = -camPos.x; // Third column, first row
translation[3][1] = -camPos.y;
translation[3][2] = -camPos.z;
glm::mat4 rotation = glm::mat4(1.0f);
rotation[0][0] = newU.x; // First column, first row
rotation[1][0] = newU.y;
rotation[2][0] = newU.z;
rotation[0][1] = newV.x; // First column, second row
rotation[1][1] = newV.y;
rotation[2][1] = newV.z;
rotation[0][2] = newN.x; // First column, third row
rotation[1][2] = newN.y;
rotation[2][2] = newN.z;
// Return lookAt matrix as combination of translation and rotation matrix
return rotation * translation; // Remember to read from right to left (first translation then rotation)
}
//broken rn
glm::mat4 camToProjMatrix(float FOV, float width, float height, float nearZ, float farZ){
float hFOV = glm::radians(FOV/2.0f);
float ar = width/height;
float A = (farZ + nearZ)/(farZ - nearZ);
float B = - (2 * nearZ * farZ)/(farZ - nearZ);
// In glm we access elements as mat[col][row] due to column-major layout
glm::mat4 projection = glm::mat4();
projection[0][0] = 1.0f / (ar * tan(hFOV)); // First column, first row
projection[1][1] = 1.0f / (tan(hFOV));
//idk why these 2 are negative
projection[2][2] = -A;
projection[2][3] = -1.0f;
projection[3][2] = B;
return projection;
}
// processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void ProcessMouseMovement(float xoffset, float yoffset, float FOV, GLboolean constrainPitch = true)
{
float xangle = -xoffset * (FOV/2) * sensitivity;//since we want to apply counter-clockwise rotation
float yangle = yoffset * (FOV/2) * sensitivity;
//updated up and direction vector using updated angles
//pitch axis: right, x
pitch += yoffset;
// make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch)
{
if (pitch > 89.0f){
pitch = 89.0f;
yoffset = 0;
}
if (pitch < -89.0f){
pitch = -89.0f;
yoffset = 0;
}
}
glm::vec3 right = glm::normalize(glm::cross(up, direction));
/* old code when simulating euler angles with Quaternions
QuaternionRotate(right, yoffset, up);
QuaternionRotate(right, yoffset, direction);
yaw axis: up, y (locked yaw to worldUp axis to prevent unwanted roll)
QuaternionRotate(worldUp, xoffset, direction);
*/
CameraRotate(worldUp, right, xangle, yangle, direction);
//by rotating direction around WorldUp we must recalculate both right and up
right = glm::normalize(glm::cross(worldUp, direction));
up = glm::normalize(glm::cross(direction, right));
}
//combined multiple quaternion
void CameraRotate(glm::vec3 axis1, glm::vec3 axis2, float angle1, float angle2, glm::vec3& point)
{
//quat 1
float angleRad1 = glm::radians(angle1);
axis1 = glm::normalize(axis1);
float w = glm::cos(angleRad1 / 2);
float v = glm::sin(angleRad1 / 2);
glm::vec3 qv = v * axis1;
glm::quat rot1 = glm::quat(w, qv);
//quat 2
float angleRad2 = glm::radians(angle2);
axis2 = glm::normalize(axis2);
w = glm::cos(angleRad2 / 2);
v = glm::sin(angleRad2 / 2);
qv = v * axis2;
glm::quat rot2 = glm::quat(w, qv);
glm::quat rot = rot1 * rot2;
point = glm::normalize(rot * point);
}
//not neccesary but cool to understand/look at
void QuaternionRotate(glm::vec3 axis, float angle, glm::vec3& point)
{
float angleRad = glm::radians(angle);
axis = glm::normalize(axis);
float w = glm::cos(angleRad / 2);
float v = glm::sin(angleRad / 2);
glm::vec3 qv = v * axis;
glm::quat rot = glm::quat(w, qv);
point = glm::normalize(rot * point);
}
// private:
glm::vec3 camPos;
glm::vec3 direction;
glm::vec3 worldUp;
glm::vec3 up;
float speed;
float sensitivity;//range 0 - 1 exculsive
float yaw;
float pitch;
};
#endif