-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathCamera3D.js
139 lines (118 loc) · 4.43 KB
/
Camera3D.js
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
// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
const CameraMovement = {
FORWARD: 0,
BACKWARD: 1,
LEFT: 2,
RIGHT: 3,
UP: 4,
DOWN: 5
}
// Default camera values
const YAW = -90.0;
const PITCH = 0.0;
const SPEED = 3.0;
const SENSITIVTY = 0.25;
const ZOOM = 45.0;
// An abstract camera class that processes input and calculates the corresponding Eular Angles, Vectors and Matrices for use in OpenGL
class Camera3D {
constructor(position = math.matrix([[0],[0],[2]]), up = math.matrix([[0],[1],[0]]), yaw=YAW, pitch=PITCH, movementSpeed=SPEED, mouseSensitivity=SENSITIVTY, zoom=ZOOM){
this.position = position;
this.worldUp = up;
this.yaw = yaw;
this.pitch = pitch;
this.movementSpeed=movementSpeed;
this.mouseSensitivity=mouseSensitivity;
this.zoom=zoom;
this.updateCameraVectors();
}
get viewMatrix(){
let lookAt = math.zeros(4,4);
set(lookAt, 0, 0, this.right._data[0][0])
set(lookAt, 0, 1, this.right._data[1][0])
set(lookAt, 0, 2, this.right._data[2][0])
set(lookAt, 1, 0, this.up._data[0][0])
set(lookAt, 1, 1, this.up._data[1][0])
set(lookAt, 1, 2, this.up._data[2][0])
set(lookAt, 2, 0, this.front._data[0][0])
set(lookAt, 2, 1, this.front._data[1][0])
set(lookAt, 2, 2, this.front._data[2][0])
set(lookAt, 3, 0, this.position._data[0][0])
set(lookAt, 3, 1, this.position._data[1][0])
set(lookAt, 3, 2, this.position._data[2][0])
return lookAt
}
projectionMatrix(w, h){
let near = 0;
let far = 100000
let one_over_tan_eyeangle = 1/math.tan(math.unit(this.zoom, 'deg'));
let aspect = w/h;
let projection = math.zeros(4,4);
set(projection, 0, 0, one_over_tan_eyeangle / aspect)
set(projection, 1, 1, one_over_tan_eyeangle)
set(projection, 2, 2, (near + far) / (near - far))
set(projection, 2, 3, 2 * (near * far) / (near - far))
set(projection, 3, 2, -1)
return projection;
}
get modelMatrix(){
return translateMatrixN(3, this.position)
}
processKeyboard(direction, deltaTime){
let velocity = this.movementSpeed * deltaTime;
if (direction == CameraMovement.FORWARD){
this.position = math.add(this.position, math.multiply(this.front, velocity));
}
if (direction == CameraMovement.BACKWARD){
this.position = math.subtract(this.position, math.multiply(this.front, velocity));
}
if (direction == CameraMovement.LEFT){
this.position = math.subtract(this.position, math.multiply(this.right, -velocity));
}
if (direction == CameraMovement.RIGHT){
this.position = math.add(this.position, math.multiply(this.right, -velocity));
}
if (direction == CameraMovement.UP){
this.position = math.add(this.position, math.multiply(this.up, -velocity));
}
if (direction == CameraMovement.DOWN){
this.position = math.subtract(this.position, math.multiply(this.up, -velocity));
}
}
// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
processMouseMovement(xoffset, yoffset, constrainPitch=true){
xoffset *= this.mouseSensitivity;
yoffset *= this.mouseSensitivity;
this.yaw -= xoffset;
this.pitch += yoffset;
// Make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch) {
if (this.pitch > 89.0)
this.pitch = 89.0;
if (this.pitch < -89.0)
this.pitch = -89.0;
}
// Update Front, Right and Up Vectors using the updated Eular angles
this.updateCameraVectors();
}
processMouseScroll(yoffset) {
if (this.zoom >= 1.0 && this.zoom <= 45.0)
this.zoom -= yoffset;
if (this.zoom <= 1.0)
this.zoom = 1.0;
if (this.zoom >= 45.0)
this.zoom = 45.0;
}
updateCameraVectors() {
// Calculate the new Front vector
let front = [];
front[0] = math.cos(math.unit(this.yaw, "deg")) * math.cos(math.unit(this.pitch, "deg"))
front[1] = math.sin(math.unit(this.pitch, "deg"))
front[2] = math.sin(math.unit(this.yaw, "deg")) * math.cos(math.unit(this.pitch, "deg"))
front = math.matrix(front)
this.front = normalized(front)
// Also re-calculate the Right and Up vector
// Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
this.right = normalized(math.flatten(math.cross(this.front, this.worldUp)))
this.up = normalized(math.flatten(math.cross(this.right, this.front)))
}
}