-
Notifications
You must be signed in to change notification settings - Fork 25
/
firstpersonmodifier.ts
108 lines (77 loc) · 3.12 KB
/
firstpersonmodifier.ts
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
/* spellchecker: disable */
import { mat4, vec2, vec3 } from 'gl-matrix';
import { m4, v3 } from './gl-matrix-extensions';
import { CameraModifier } from './cameramodifier';
/* spellchecker: enable */
/**
* Math for camera modification based on the first person metaphor.
*/
export class FirstPersonModifier extends CameraModifier {
protected static readonly DEFAULT_SENSITIVITY = 0.0008;
/**
* Current rotation matrix.
*/
protected _rotation: mat4 = mat4.create();
/** @see {@link sensitivity} */
protected _sensitivity: number = FirstPersonModifier.DEFAULT_SENSITIVITY;
/**
* Initiate a new camera modification at a specific event position.
* @param point - Position of the current event to start the modification at.
*/
initiate(point: vec2): void {
Object.assign(this._reference, this._camera);
/* Retrieve initial event position. */
this._initialPoint = point;
}
/**
* Update the ... .r.t. a specific event position.
* @param point - Position of the current event used to update the yaw and pitch.
*/
process(point: vec2, movement?: vec2): void {
/* Current event position is always the same as initial, when pointer lock is active. */
this._currentPoint = point;
const magnitudes = vec2.create();
if (movement === undefined) {
vec2.subtract(magnitudes, this._initialPoint, this._currentPoint);
} else {
vec2.copy(magnitudes, movement);
}
vec2.scale(magnitudes, magnitudes, window.devicePixelRatio * this._sensitivity);
/* Difference between two subsequent events, thus, initial position is reset. */
vec2.copy(this._initialPoint, this._currentPoint);
const centerToEye = vec3.sub(v3(), this._reference.eye, this._reference.center);
vec3.normalize(centerToEye, centerToEye);
const strafe = vec3.cross(v3(), centerToEye, this._reference.up);
const yaw = mat4.fromRotation(m4(), -magnitudes[0], this._reference.up);
const pitch = mat4.fromRotation(m4(), magnitudes[1], strafe);
mat4.mul(this._rotation, pitch, yaw);
this.update();
}
/**
* Actually applies the trackball rotation to the given camera.
*/
update(): void {
if (this._camera === undefined) {
return;
}
const T = mat4.fromTranslation(m4(), this._reference.eye);
mat4.multiply(T, T, this._rotation);
mat4.translate(T, T, vec3.negate(v3(), this._reference.eye));
// const up = vec3.transformMat4(v3(), [0.0, 1.0, 0.0], this._rotation);
// const eye = vec3.transformMat4(v3(), this._reference.eye, T);
const center = vec3.transformMat4(v3(), this._reference.center, T);
// this._camera.up = up;
// this._camera.eye = eye;
this._camera.center = center;
Object.assign(this._reference, this._camera);
}
/**
* Rotational sensitivity.
*/
set sensitivity(sensitivity: number) {
this._sensitivity = sensitivity;
}
get sensitivity(): number {
return this._sensitivity;
}
}