-
Notifications
You must be signed in to change notification settings - Fork 46
/
matrix4.ts
178 lines (161 loc) · 5.17 KB
/
matrix4.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
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
import { Matrix } from "@pixi/math"
import { ObservablePoint3D } from "./observable-point"
import { ObservableQuaternion } from "./observable-quaternion"
import { Mat4 } from "../math/mat4"
import { Vec3 } from "../math/vec3"
import { Vec4 } from "../math/vec4"
import { MatrixComponent } from "./matrix-component"
import { Quat } from "../math/quat"
import { TransformId } from "./transform-id"
/**
* Represents a 4x4 matrix.
*/
export class Matrix4 extends Matrix implements TransformId {
private _transformId = 0
private _position?: MatrixComponent
private _scaling?: MatrixComponent
private _rotation?: MatrixComponent
private _up?: MatrixComponent
private _down?: MatrixComponent
private _forward?: MatrixComponent
private _left?: MatrixComponent
private _right?: MatrixComponent
private _backward?: MatrixComponent
get transformId() {
return this._transformId
}
/** The array containing the matrix data. */
public array: Float32Array
/**
* Creates a new transform matrix using the specified matrix array.
* @param array The matrix array, expected length is 16. If empty, an identity
* matrix is used by default.
*/
constructor(array?: ArrayLike<number>) {
super()
if (array) {
this.array = new Float32Array(array)
} else {
this.array = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
}
}
toArray(transpose: boolean, out?: Float32Array) {
if (transpose) {
return Mat4.transpose(this.array, out)
}
return out ? Mat4.copy(this.array, out) : this.array
}
/** Returns the position component of the matrix. */
get position() {
if (!this._position) {
this._position = new MatrixComponent(this, 3, data => {
Mat4.getTranslation(this.array, data)
})
}
return this._position.array
}
/** Returns the scaling component of the matrix. */
get scaling() {
if (!this._scaling) {
this._scaling = new MatrixComponent(this, 3, data => {
Mat4.getScaling(this.array, data)
})
}
return this._scaling.array
}
/** Returns the rotation quaternion of the matrix. */
get rotation() {
if (!this._rotation) {
let matrix = new Float32Array(16)
this._rotation = new MatrixComponent(this, 4, data => {
// To extract a correct rotation, the scaling component must be eliminated.
for (let col of [0, 1, 2]) {
matrix[col + 0] = this.array[col + 0] / this.scaling[0]
matrix[col + 4] = this.array[col + 4] / this.scaling[1]
matrix[col + 8] = this.array[col + 8] / this.scaling[2]
}
Quat.normalize(Mat4.getRotation(matrix, data), data)
})
}
return this._rotation.array
}
/** Returns the up vector of the matrix. */
get up() {
if (!this._up) {
this._up = new MatrixComponent(this, 3, data => {
Vec3.normalize(Vec3.set(this.array[4], this.array[5], this.array[6], data), data)
})
}
return this._up.array
}
/** Returns the down vector of the matrix. */
get down() {
if (!this._down) {
this._down = new MatrixComponent(this, 3, data => {
Vec3.negate(this.up, data)
})
}
return this._down.array
}
/** Returns the left vector of the matrix. */
get right() {
if (!this._right) {
this._right = new MatrixComponent(this, 3, data => {
Vec3.negate(this.left, data)
})
}
return this._right.array
}
/** Returns the right vector of the matrix. */
get left() {
if (!this._left) {
this._left = new MatrixComponent(this, 3, data => {
Vec3.normalize(Vec3.cross(this.up, this.forward, data), data)
})
}
return this._left.array
}
/** Returns the forward vector of the matrix. */
get forward() {
if (!this._forward) {
this._forward = new MatrixComponent(this, 3, data => {
Vec3.normalize(Vec3.set(this.array[8], this.array[9], this.array[10], data), data)
})
}
return this._forward.array
}
/** Returns the backward vector of the matrix. */
get backward() {
if (!this._backward) {
this._backward = new MatrixComponent(this, 3, data => {
Vec3.negate(this.forward, data)
})
}
return this._backward.array
}
copyFrom(matrix: Matrix4) {
if (matrix instanceof Matrix4) {
Mat4.copy(matrix.array, this.array); this._transformId++
}
return this
}
/**
* Sets the rotation, position and scale components.
* @param rotation The rotation to set.
* @param position The position to set.
* @param scaling The scale to set.
*/
setFromRotationPositionScale(rotation: ObservableQuaternion, position: ObservablePoint3D, scaling: ObservablePoint3D) {
Vec4.set(rotation.x, rotation.y, rotation.z, rotation.w, this.rotation)
Vec3.set(scaling.x, scaling.y, scaling.z, this.scaling)
Vec3.set(position.x, position.y, position.z, this.position)
Mat4.fromRotationTranslationScale(this.rotation, this.position, this.scaling, this.array); this._transformId++
}
/**
* Multiplies this matrix with another matrix.
* @param matrix The matrix to multiply with.
*/
multiply(matrix: Matrix4) {
Mat4.multiply(matrix.array, this.array, this.array); this._transformId++
}
}