glmaths 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +952 -0
- package/benchmark.js +747 -0
- package/dist/cjs/glmaths.d.ts +12053 -0
- package/dist/cjs/glmaths.js +6496 -0
- package/dist/cjs/glmaths.js.map +1 -0
- package/dist/cjs/glmaths.min.js +2 -0
- package/dist/cjs/glmaths.min.js.map +1 -0
- package/dist/esm/glmaths.d.ts +12053 -0
- package/dist/esm/glmaths.js +6453 -0
- package/dist/esm/glmaths.js.map +1 -0
- package/dist/esm/glmaths.min.js +2 -0
- package/dist/esm/glmaths.min.js.map +1 -0
- package/dist/glmaths.d.ts +12053 -0
- package/dist/glmaths.js +6501 -0
- package/dist/glmaths.js.map +1 -0
- package/dist/glmaths.min.js +2 -0
- package/dist/glmaths.min.js.map +1 -0
- package/docs.js +64 -0
- package/package.json +37 -0
- package/rollup.config.js +70 -0
- package/src/index.ts +19 -0
- package/src/internalUtils.ts +78 -0
- package/src/mat2.ts +324 -0
- package/src/mat2x3.ts +328 -0
- package/src/mat3.ts +629 -0
- package/src/mat4.ts +1319 -0
- package/src/quat.ts +819 -0
- package/src/quat2.ts +412 -0
- package/src/utils.ts +248 -0
- package/src/vec2.ts +798 -0
- package/src/vec3.ts +1069 -0
- package/src/vec4.ts +810 -0
- package/tests/mat2.test.ts +277 -0
- package/tests/mat2x3.test.ts +217 -0
- package/tests/mat3.test.ts +306 -0
- package/tests/mat4.test.ts +586 -0
- package/tests/quat.test.ts +418 -0
- package/tests/quat2.test.ts +222 -0
- package/tests/utils.test.ts +115 -0
- package/tests/vec2.test.ts +617 -0
- package/tests/vec3.test.ts +649 -0
- package/tests/vec4.test.ts +390 -0
- package/tsconfig.json +17 -0
- package/tsconfig.test.json +8 -0
package/src/quat.ts
ADDED
|
@@ -0,0 +1,819 @@
|
|
|
1
|
+
import glm from '.'
|
|
2
|
+
import { vec3, Vec3 } from './vec3'
|
|
3
|
+
import { vec4, Vec4 } from './vec4'
|
|
4
|
+
import { Mat3 } from './mat3'
|
|
5
|
+
import { Mat4 } from './mat4'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Quaternion for 3D rotations
|
|
9
|
+
* @extends Vec4
|
|
10
|
+
*/
|
|
11
|
+
export class Quat extends Float32Array {
|
|
12
|
+
|
|
13
|
+
static get identity() { return new Quat(0, 0, 0, 1) }
|
|
14
|
+
static get Identity() { return new Quat(0, 0, 0, 1) }
|
|
15
|
+
static get IDENTITY() { return new Quat(0, 0, 0, 1) }
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new quaternion
|
|
19
|
+
*
|
|
20
|
+
* @param {Number} x X component, defaults to 0
|
|
21
|
+
* @param {Number} y Y component, defaults to 0
|
|
22
|
+
* @param {Number} z Z component, defaults to 0
|
|
23
|
+
* @param {Number} w W component, defaults to 1
|
|
24
|
+
*/
|
|
25
|
+
constructor(x = 0, y = 0, z = 0, w = 1) {
|
|
26
|
+
super(4)
|
|
27
|
+
this[0] = x
|
|
28
|
+
this[1] = y
|
|
29
|
+
this[2] = z
|
|
30
|
+
this[3] = w
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Calculates the Hamilton product of two quaternions
|
|
35
|
+
*
|
|
36
|
+
* @param {Quat} b the second operand
|
|
37
|
+
* @param {Quat} out the receiving quaternion, defaults to this
|
|
38
|
+
* @returns {Quat} out
|
|
39
|
+
*/
|
|
40
|
+
multiply(b: Quat | number, out: Quat = glm.ALWAYS_COPY ? new Quat() : this): Quat {
|
|
41
|
+
if (typeof b === 'number') {
|
|
42
|
+
out[0] = this[0] * b
|
|
43
|
+
out[1] = this[1] * b
|
|
44
|
+
out[2] = this[2] * b
|
|
45
|
+
out[3] = this[3] * b
|
|
46
|
+
return out!
|
|
47
|
+
}
|
|
48
|
+
const ax = this[0], ay = this[1], az = this[2], aw = this[3]
|
|
49
|
+
const bx = b[0], by = b[1], bz = b[2], bw = b[3]
|
|
50
|
+
out[0] = ax * bw + aw * bx + ay * bz - az * by
|
|
51
|
+
out[1] = ay * bw + aw * by + az * bx - ax * bz
|
|
52
|
+
out[2] = az * bw + aw * bz + ax * by - ay * bx
|
|
53
|
+
out[3] = aw * bw - ax * bx - ay * by - az * bz
|
|
54
|
+
return out
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Creates a quaternion from the given axis and angle of rotation
|
|
59
|
+
*
|
|
60
|
+
* @param {Vec3} axis the axis around which to rotate
|
|
61
|
+
* @param {Number} rad the angle in radians
|
|
62
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
63
|
+
* @returns {Quat} out
|
|
64
|
+
*/
|
|
65
|
+
static fromAxisAngle(axis: Vec3, rad: number, out = quat()): Quat {
|
|
66
|
+
rad *= 0.5
|
|
67
|
+
const s = Math.sin(rad)
|
|
68
|
+
out[0] = s * axis[0]
|
|
69
|
+
out[1] = s * axis[1]
|
|
70
|
+
out[2] = s * axis[2]
|
|
71
|
+
out[3] = Math.cos(rad)
|
|
72
|
+
return out
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Sets a quaternion to the given axis and angle of rotation
|
|
77
|
+
*
|
|
78
|
+
* @param {Vec3} axis the axis around which to rotate
|
|
79
|
+
* @param {Number} rad the angle in radians
|
|
80
|
+
* @param {Quat} out the receiving quaternion, defaults to this
|
|
81
|
+
* @returns {Quat} out
|
|
82
|
+
*/
|
|
83
|
+
setAxisAngle(axis: Vec3, rad: number, out = glm.ALWAYS_COPY ? quat() : this): Quat {
|
|
84
|
+
rad *= 0.5
|
|
85
|
+
const s = Math.sin(rad)
|
|
86
|
+
out[0] = s * axis[0]
|
|
87
|
+
out[1] = s * axis[1]
|
|
88
|
+
out[2] = s * axis[2]
|
|
89
|
+
out[3] = Math.cos(rad)
|
|
90
|
+
return out
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Gets the rotation axis and angle for a given
|
|
95
|
+
* quaternion. If a quaternion is created with
|
|
96
|
+
* setAxisAngle, this method will return the same
|
|
97
|
+
* values as providied in the original parameter list
|
|
98
|
+
* OR functionally equivalent values.
|
|
99
|
+
* Example: The quaternion formed by axis [0, 0, 1] and
|
|
100
|
+
* angle -90 is the same as the quaternion formed by
|
|
101
|
+
* [0, 0, 1] and 270. This method favors the latter.
|
|
102
|
+
* @param {Vec3} out_axis axis to return of the rotation
|
|
103
|
+
* @returns {Number} angle, in radians, of the rotation
|
|
104
|
+
*/
|
|
105
|
+
getAxisAngle(out_axis: Vec3) {
|
|
106
|
+
const rad = Math.acos(this[3]) * 2.0
|
|
107
|
+
const s = Math.sin(rad / 2.0)
|
|
108
|
+
if (out_axis) {
|
|
109
|
+
if (s > glm.EPSILON) {
|
|
110
|
+
out_axis[0] = this[0] / s
|
|
111
|
+
out_axis[1] = this[1] / s
|
|
112
|
+
out_axis[2] = this[2] / s
|
|
113
|
+
} else {
|
|
114
|
+
out_axis[0] = 1
|
|
115
|
+
out_axis[1] = out_axis[2] = 0
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return rad
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Gets the angular distance between two unit quaternions
|
|
123
|
+
*
|
|
124
|
+
* @param {Quat} a Origin unit quaternion
|
|
125
|
+
* @param {Quat} b Destination unit quaternion
|
|
126
|
+
* @returns {Number} Angle, in radians, between the two quaternions
|
|
127
|
+
*/
|
|
128
|
+
static angle(a: Quat, b: Quat) {
|
|
129
|
+
const dotproduct = Quat.dot(a, b)
|
|
130
|
+
return Math.acos(2 * dotproduct * dotproduct - 1)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Gets the angular distance between two unit quaternions
|
|
135
|
+
*
|
|
136
|
+
* @param {Quat} a Origin unit quaternion
|
|
137
|
+
* @param {Quat} b Destination unit quaternion
|
|
138
|
+
* @return {Number} Angle, in radians, between the two quaternions
|
|
139
|
+
*/
|
|
140
|
+
static getAngle: (a: Quat, b: Quat) => number
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Rotates a quaternion by the given angle about the X axis
|
|
144
|
+
*
|
|
145
|
+
* @param {Number} rad angle in radians to rotate
|
|
146
|
+
* @param {Quat} out the receiving quaternion, defaults to this
|
|
147
|
+
* @returns {Quat} out
|
|
148
|
+
*/
|
|
149
|
+
rotateX(rad: number, out = glm.ALWAYS_COPY ? quat() : this) {
|
|
150
|
+
rad *= 0.5
|
|
151
|
+
const ax = this[0], ay = this[1], az = this[2], aw = this[3]
|
|
152
|
+
const bx = Math.sin(rad), bw = Math.cos(rad)
|
|
153
|
+
out[0] = ax * bw + aw * bx
|
|
154
|
+
out[1] = ay * bw + az * bx
|
|
155
|
+
out[2] = az * bw - ay * bx
|
|
156
|
+
out[3] = aw * bw - ax * bx
|
|
157
|
+
return out
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Rotates a quaternion by the given angle about the Y axis
|
|
162
|
+
*
|
|
163
|
+
* @param {Number} rad angle in radians to rotate
|
|
164
|
+
* @param {Quat} out the receiving quaternion, defaults to this
|
|
165
|
+
* @returns {Quat} out
|
|
166
|
+
*/
|
|
167
|
+
rotateY(rad: number, out = glm.ALWAYS_COPY ? quat() : this) {
|
|
168
|
+
rad *= 0.5
|
|
169
|
+
const ax = this[0], ay = this[1], az = this[2], aw = this[3]
|
|
170
|
+
const by = Math.sin(rad), bw = Math.cos(rad)
|
|
171
|
+
out[0] = ax * bw - az * by
|
|
172
|
+
out[1] = ay * bw + aw * by
|
|
173
|
+
out[2] = az * bw + ax * by
|
|
174
|
+
out[3] = aw * bw - ay * by
|
|
175
|
+
return out
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Rotates a quaternion by the given angle about the Z axis
|
|
179
|
+
*
|
|
180
|
+
* @param {Number} rad angle in radians to rotate
|
|
181
|
+
* @param {Quat} out the receiving quaternion, defaults to this
|
|
182
|
+
* @returns {Quat} out
|
|
183
|
+
*/
|
|
184
|
+
rotateZ(rad: number, out = glm.ALWAYS_COPY ? quat() : this) {
|
|
185
|
+
rad *= 0.5
|
|
186
|
+
const ax = this[0], ay = this[1], az = this[2], aw = this[3]
|
|
187
|
+
const bz = Math.sin(rad), bw = Math.cos(rad)
|
|
188
|
+
out[0] = ax * bw + ay * bz;
|
|
189
|
+
out[1] = ay * bw - ax * bz;
|
|
190
|
+
out[2] = az * bw + aw * bz;
|
|
191
|
+
out[3] = aw * bw - az * bz;
|
|
192
|
+
return out
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Calculates the W component of a quaternion from the X, Y, and Z components
|
|
197
|
+
*
|
|
198
|
+
* @returns {Number} the W component
|
|
199
|
+
*/
|
|
200
|
+
calculateW() {
|
|
201
|
+
const x = this[0], y = this[1], z = this[2]
|
|
202
|
+
return Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z))
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Calculates the exponential of a unit quaternion
|
|
207
|
+
*
|
|
208
|
+
* @param {Quat} q the quaternion to exponentiate
|
|
209
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
210
|
+
* @returns {Quat} out
|
|
211
|
+
*/
|
|
212
|
+
static exp(q: Quat, out = quat()): Quat {
|
|
213
|
+
const x = q[0], y = q[1], z = q[2], w = q[3]
|
|
214
|
+
const r = Math.sqrt(x * x + y * y + z * z)
|
|
215
|
+
const et = Math.exp(w)
|
|
216
|
+
const s = r > 0 ? (et * Math.sin(r)) / r : 0
|
|
217
|
+
out[0] = x * s
|
|
218
|
+
out[1] = y * s
|
|
219
|
+
out[2] = z * s
|
|
220
|
+
out[3] = et * Math.cos(r)
|
|
221
|
+
return out
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Calculates the exponential of the unit quaternion
|
|
225
|
+
*
|
|
226
|
+
* @param {Quat} out the receiving quaternion, defaults to this
|
|
227
|
+
* @returns {Quat} out
|
|
228
|
+
*/
|
|
229
|
+
exp(out = glm.ALWAYS_COPY ? quat() : this): Quat {
|
|
230
|
+
const x = this[0], y = this[1], z = this[2], w = this[3]
|
|
231
|
+
const r = Math.sqrt(x * x + y * y + z * z)
|
|
232
|
+
const et = Math.exp(w)
|
|
233
|
+
const s = r > 0 ? (et * Math.sin(r)) / r : 0
|
|
234
|
+
out[0] = x * s
|
|
235
|
+
out[1] = y * s
|
|
236
|
+
out[2] = z * s
|
|
237
|
+
out[3] = et * Math.cos(r)
|
|
238
|
+
return out
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Calculates the natural logarithm of a unit quaternion
|
|
243
|
+
*
|
|
244
|
+
* @param {Quat} q the quaternion to take the logarithm of
|
|
245
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
246
|
+
* @returns {Quat} out
|
|
247
|
+
*/
|
|
248
|
+
static ln(q: Quat, out = quat()): Quat {
|
|
249
|
+
const x = q[0], y = q[1], z = q[2], w = q[3]
|
|
250
|
+
const r = Math.sqrt(x * x + y * y + z * z)
|
|
251
|
+
const t = r > 0 ? Math.atan2(r, w) / r : 0
|
|
252
|
+
out[0] = x * t
|
|
253
|
+
out[1] = y * t
|
|
254
|
+
out[2] = z * t
|
|
255
|
+
out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w)
|
|
256
|
+
return out
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Calculates the natural logarithm of the unit quaternion
|
|
260
|
+
*
|
|
261
|
+
* @param {Quat} out the receiving quaternion, defaults to this
|
|
262
|
+
* @returns {Quat} out
|
|
263
|
+
*/
|
|
264
|
+
ln(out = glm.ALWAYS_COPY ? quat() : this): Quat {
|
|
265
|
+
const x = this[0], y = this[1], z = this[2], w = this[3]
|
|
266
|
+
const r = Math.sqrt(x * x + y * y + z * z)
|
|
267
|
+
const t = r > 0 ? Math.atan2(r, w) / r : 0
|
|
268
|
+
out[0] = x * t
|
|
269
|
+
out[1] = y * t
|
|
270
|
+
out[2] = z * t
|
|
271
|
+
out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w)
|
|
272
|
+
return out
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Raises a quaternion to a scalar power
|
|
277
|
+
*
|
|
278
|
+
* @param {Number} b the power to raise the quaternion to
|
|
279
|
+
* @returns {Quat} this
|
|
280
|
+
*/
|
|
281
|
+
pow(b: number) {
|
|
282
|
+
this.ln()
|
|
283
|
+
this.scale(b)
|
|
284
|
+
this.exp()
|
|
285
|
+
return this
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Performs a spherical linear interpolation between two quaternions
|
|
290
|
+
*
|
|
291
|
+
* @param {Quat} a the first operand
|
|
292
|
+
* @param {Quat} b the second operand
|
|
293
|
+
* @param {Number} t interpolation amount, in the range [0-1], between the two inputs
|
|
294
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
295
|
+
* @returns {Quat} out
|
|
296
|
+
*/
|
|
297
|
+
static slerp(a: Quat, b: Quat, t: number, out = quat()): Quat {
|
|
298
|
+
let ax = a[0], ay = a[1], az = a[2], aw = a[3]
|
|
299
|
+
let bx = b[0], by = b[1], bz = b[2], bw = b[3]
|
|
300
|
+
|
|
301
|
+
let omega, cosom, sinom, scale0, scale1;
|
|
302
|
+
// calc cosine
|
|
303
|
+
cosom = ax * bx + ay * by + az * bz + aw * bw;
|
|
304
|
+
// adjust signs (if necessary)
|
|
305
|
+
if (cosom < 0.0) {
|
|
306
|
+
cosom = -cosom;
|
|
307
|
+
bx = -bx;
|
|
308
|
+
by = -by;
|
|
309
|
+
bz = -bz;
|
|
310
|
+
bw = -bw;
|
|
311
|
+
}
|
|
312
|
+
// calculate coefficients
|
|
313
|
+
if (1.0 - cosom > glm.EPSILON) {
|
|
314
|
+
// standard case (slerp)
|
|
315
|
+
omega = Math.acos(cosom);
|
|
316
|
+
sinom = Math.sin(omega);
|
|
317
|
+
scale0 = Math.sin((1.0 - t) * omega) / sinom;
|
|
318
|
+
scale1 = Math.sin(t * omega) / sinom;
|
|
319
|
+
} else {
|
|
320
|
+
// "from" and "to" quaternions are very close
|
|
321
|
+
// ... so we can do a linear interpolation
|
|
322
|
+
scale0 = 1.0 - t;
|
|
323
|
+
scale1 = t;
|
|
324
|
+
}
|
|
325
|
+
// calculate final values
|
|
326
|
+
out[0] = scale0 * ax + scale1 * bx
|
|
327
|
+
out[1] = scale0 * ay + scale1 * by
|
|
328
|
+
out[2] = scale0 * az + scale1 * bz
|
|
329
|
+
out[3] = scale0 * aw + scale1 * bw
|
|
330
|
+
return out
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Performs a spherical linear interpolation between a quaternion and b
|
|
334
|
+
*
|
|
335
|
+
* @param {Quat} b the second operand
|
|
336
|
+
* @param {Number} t interpolation amount, in the range [0-1], between the two inputs
|
|
337
|
+
* @param {Quat} out the receiving quaternion, defaults to this
|
|
338
|
+
* @returns {Quat} out
|
|
339
|
+
*/
|
|
340
|
+
slerp(b: Quat, t: number, out = glm.ALWAYS_COPY ? quat() : this): Quat {
|
|
341
|
+
let ax = this[0], ay = this[1], az = this[2], aw = this[3]
|
|
342
|
+
let bx = b[0], by = b[1], bz = b[2], bw = b[3]
|
|
343
|
+
|
|
344
|
+
let omega, cosom, sinom, scale0, scale1;
|
|
345
|
+
// calc cosine
|
|
346
|
+
cosom = ax * bx + ay * by + az * bz + aw * bw;
|
|
347
|
+
// adjust signs (if necessary)
|
|
348
|
+
if (cosom < 0.0) {
|
|
349
|
+
cosom = -cosom;
|
|
350
|
+
bx = -bx;
|
|
351
|
+
by = -by;
|
|
352
|
+
bz = -bz;
|
|
353
|
+
bw = -bw;
|
|
354
|
+
}
|
|
355
|
+
// calculate coefficients
|
|
356
|
+
if (1.0 - cosom > glm.EPSILON) {
|
|
357
|
+
// standard case (slerp)
|
|
358
|
+
omega = Math.acos(cosom);
|
|
359
|
+
sinom = Math.sin(omega);
|
|
360
|
+
scale0 = Math.sin((1.0 - t) * omega) / sinom;
|
|
361
|
+
scale1 = Math.sin(t * omega) / sinom;
|
|
362
|
+
} else {
|
|
363
|
+
// "from" and "to" quaternions are very close
|
|
364
|
+
// ... so we can do a linear interpolation
|
|
365
|
+
scale0 = 1.0 - t;
|
|
366
|
+
scale1 = t;
|
|
367
|
+
}
|
|
368
|
+
// calculate final values
|
|
369
|
+
out[0] = scale0 * ax + scale1 * bx
|
|
370
|
+
out[1] = scale0 * ay + scale1 * by
|
|
371
|
+
out[2] = scale0 * az + scale1 * bz
|
|
372
|
+
out[3] = scale0 * aw + scale1 * bw
|
|
373
|
+
return out
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Generates a random unit quaternion
|
|
378
|
+
*
|
|
379
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
380
|
+
* @returns {Quat} out
|
|
381
|
+
*/
|
|
382
|
+
static random(out = quat()) {
|
|
383
|
+
// Implementation of http://planning.cs.uiuc.edu/node198.html
|
|
384
|
+
// TODO: Calling random 3 times is probably not the fastest solution
|
|
385
|
+
let u1 = glm.RANDOM()
|
|
386
|
+
let u2 = glm.RANDOM()
|
|
387
|
+
let u3 = glm.RANDOM()
|
|
388
|
+
let sqrt1MinusU1 = Math.sqrt(1 - u1)
|
|
389
|
+
let sqrtU1 = Math.sqrt(u1)
|
|
390
|
+
out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2)
|
|
391
|
+
out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2)
|
|
392
|
+
out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3)
|
|
393
|
+
out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3)
|
|
394
|
+
return out
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* Calculates the inverse of a quaternion
|
|
399
|
+
*
|
|
400
|
+
* @param {Quat} q the source quaternion
|
|
401
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
402
|
+
* @returns {Quat} out
|
|
403
|
+
*/
|
|
404
|
+
static invert(q: Quat, out = quat()) {
|
|
405
|
+
const a0 = q[0], a1 = q[1], a2 = q[2], a3 = q[3]
|
|
406
|
+
const dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
|
|
407
|
+
const invDot = dot ? 1.0 / dot : 0;
|
|
408
|
+
// TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
|
|
409
|
+
out[0] = -a0 * invDot
|
|
410
|
+
out[1] = -a1 * invDot
|
|
411
|
+
out[2] = -a2 * invDot
|
|
412
|
+
out[3] = a3 * invDot
|
|
413
|
+
return out
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Calculates the inverse of a quaternion
|
|
417
|
+
*
|
|
418
|
+
* @param {Quat} out the receiving quaternion, defaults to this
|
|
419
|
+
* @returns {Quat} out
|
|
420
|
+
*/
|
|
421
|
+
invert(out = glm.ALWAYS_COPY ? quat() : this) {
|
|
422
|
+
const a0 = this[0], a1 = this[1], a2 = this[2], a3 = this[3]
|
|
423
|
+
const dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3;
|
|
424
|
+
const invDot = dot ? 1.0 / dot : 0;
|
|
425
|
+
// TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
|
|
426
|
+
out[0] = -a0 * invDot
|
|
427
|
+
out[1] = -a1 * invDot
|
|
428
|
+
out[2] = -a2 * invDot
|
|
429
|
+
out[3] = a3 * invDot
|
|
430
|
+
return out
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Calculates the conjugate of a quaternion
|
|
435
|
+
*
|
|
436
|
+
* @param {Quat} q the source quaternion
|
|
437
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
438
|
+
* @returns {Quat} out
|
|
439
|
+
*/
|
|
440
|
+
static conjugate(q: Quat, out = quat()): Quat {
|
|
441
|
+
out[0] = -q[0]
|
|
442
|
+
out[1] = -q[1]
|
|
443
|
+
out[2] = -q[2]
|
|
444
|
+
out[3] = q[3]
|
|
445
|
+
return out
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Calculates the conjugate of a quaternion
|
|
449
|
+
*
|
|
450
|
+
* @param {Quat} out the receiving quaternion, defaults to this
|
|
451
|
+
* @returns {Quat} out
|
|
452
|
+
*/
|
|
453
|
+
conjugate(out = glm.ALWAYS_COPY ? quat() : this): Quat {
|
|
454
|
+
out[0] = -this[0]
|
|
455
|
+
out[1] = -this[1]
|
|
456
|
+
out[2] = -this[2]
|
|
457
|
+
out[3] = this[3]
|
|
458
|
+
return out
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Creates a quaternion from the given 3x3 rotation matrix
|
|
463
|
+
*
|
|
464
|
+
* @param {Mat3} m the rotation matrix
|
|
465
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
466
|
+
* @returns {Quat} out
|
|
467
|
+
*/
|
|
468
|
+
static fromMat3(m: Mat3, out = quat()): Quat {
|
|
469
|
+
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
|
|
470
|
+
// article "Quaternion Calculus and Fast Animation".
|
|
471
|
+
const fTrace = m[0] + m[4] + m[8]
|
|
472
|
+
let fRoot
|
|
473
|
+
if (fTrace > 0.0) {
|
|
474
|
+
// |w| > 1/2, may as well choose w > 1/2
|
|
475
|
+
fRoot = Math.sqrt(fTrace + 1.0); // 2w
|
|
476
|
+
out[3] = 0.5 * fRoot
|
|
477
|
+
fRoot = 0.5 / fRoot // 1/(4w)
|
|
478
|
+
out[0] = (m[5] - m[7]) * fRoot
|
|
479
|
+
out[1] = (m[6] - m[2]) * fRoot
|
|
480
|
+
out[2] = (m[1] - m[3]) * fRoot
|
|
481
|
+
} else {
|
|
482
|
+
// |w| <= 1/2
|
|
483
|
+
let i = 0
|
|
484
|
+
if (m[4] > m[0]) i = 1
|
|
485
|
+
if (m[8] > m[i * 3 + i]) i = 2
|
|
486
|
+
let j = (i + 1) % 3
|
|
487
|
+
let k = (i + 2) % 3
|
|
488
|
+
fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0)
|
|
489
|
+
out[i] = 0.5 * fRoot
|
|
490
|
+
fRoot = 0.5 / fRoot
|
|
491
|
+
out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot
|
|
492
|
+
out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot
|
|
493
|
+
out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
|
|
494
|
+
}
|
|
495
|
+
return out;
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Creates a quaternion from the given Euler angle x, y, z using the given order
|
|
499
|
+
*
|
|
500
|
+
* @param {Number} x rotation around X axis in degrees
|
|
501
|
+
* @param {Number} y rotation around Y axis in degrees
|
|
502
|
+
* @param {Number} z rotation around Z axis in degrees
|
|
503
|
+
* @param {String} order angle order, defaults to ANGLE_ORDER
|
|
504
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
505
|
+
* @returns {Quat} out
|
|
506
|
+
*/
|
|
507
|
+
static fromEuler(x: number, y: number, z: number, order = glm.ANGLE_ORDER, out = quat()) {
|
|
508
|
+
let halfToRad = Math.PI / 360
|
|
509
|
+
x *= halfToRad
|
|
510
|
+
z *= halfToRad
|
|
511
|
+
y *= halfToRad
|
|
512
|
+
let sx = Math.sin(x)
|
|
513
|
+
let cx = Math.cos(x)
|
|
514
|
+
let sy = Math.sin(y)
|
|
515
|
+
let cy = Math.cos(y)
|
|
516
|
+
let sz = Math.sin(z)
|
|
517
|
+
let cz = Math.cos(z)
|
|
518
|
+
switch (order) {
|
|
519
|
+
case "xyz":
|
|
520
|
+
out[0] = sx * cy * cz + cx * sy * sz;
|
|
521
|
+
out[1] = cx * sy * cz - sx * cy * sz;
|
|
522
|
+
out[2] = cx * cy * sz + sx * sy * cz;
|
|
523
|
+
out[3] = cx * cy * cz - sx * sy * sz;
|
|
524
|
+
break;
|
|
525
|
+
case "xzy":
|
|
526
|
+
out[0] = sx * cy * cz - cx * sy * sz;
|
|
527
|
+
out[1] = cx * sy * cz - sx * cy * sz;
|
|
528
|
+
out[2] = cx * cy * sz + sx * sy * cz;
|
|
529
|
+
out[3] = cx * cy * cz + sx * sy * sz;
|
|
530
|
+
break;
|
|
531
|
+
case "yxz":
|
|
532
|
+
out[0] = sx * cy * cz + cx * sy * sz;
|
|
533
|
+
out[1] = cx * sy * cz - sx * cy * sz;
|
|
534
|
+
out[2] = cx * cy * sz - sx * sy * cz;
|
|
535
|
+
out[3] = cx * cy * cz + sx * sy * sz;
|
|
536
|
+
break;
|
|
537
|
+
case "yzx":
|
|
538
|
+
out[0] = sx * cy * cz + cx * sy * sz;
|
|
539
|
+
out[1] = cx * sy * cz + sx * cy * sz;
|
|
540
|
+
out[2] = cx * cy * sz - sx * sy * cz;
|
|
541
|
+
out[3] = cx * cy * cz - sx * sy * sz;
|
|
542
|
+
break;
|
|
543
|
+
case "zxy":
|
|
544
|
+
out[0] = sx * cy * cz - cx * sy * sz;
|
|
545
|
+
out[1] = cx * sy * cz + sx * cy * sz;
|
|
546
|
+
out[2] = cx * cy * sz + sx * sy * cz;
|
|
547
|
+
out[3] = cx * cy * cz - sx * sy * sz;
|
|
548
|
+
break;
|
|
549
|
+
case "zyx":
|
|
550
|
+
out[0] = sx * cy * cz - cx * sy * sz;
|
|
551
|
+
out[1] = cx * sy * cz + sx * cy * sz;
|
|
552
|
+
out[2] = cx * cy * sz - sx * sy * cz;
|
|
553
|
+
out[3] = cx * cy * cz + sx * sy * sz;
|
|
554
|
+
break;
|
|
555
|
+
default:
|
|
556
|
+
throw new Error('Unknown angle order ' + order);
|
|
557
|
+
}
|
|
558
|
+
return out
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Returns a string representation of a quaternion
|
|
563
|
+
*
|
|
564
|
+
* @returns {String} string representation of the quaternion
|
|
565
|
+
*/
|
|
566
|
+
toString() {
|
|
567
|
+
return `quat(${this[0]}, ${this[1]}, ${this[2]}, ${this[3]})`
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Returns dot product of two quaternions
|
|
572
|
+
*
|
|
573
|
+
* @param {Quat} a the first quaternion
|
|
574
|
+
* @param {Quat} b the second quaternion
|
|
575
|
+
* @returns {Number} the dot product
|
|
576
|
+
*/
|
|
577
|
+
static dot(a: Quat, b: Quat): number {
|
|
578
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Returns dot product of this and other quaternion
|
|
583
|
+
*
|
|
584
|
+
* @param {Quat} a the first quaternion
|
|
585
|
+
* @param {Quat} b the second quaternion
|
|
586
|
+
* @returns {Number} the dot product
|
|
587
|
+
*/
|
|
588
|
+
dot(b: Quat): number {
|
|
589
|
+
return this[0] * b[0] + this[1] * b[1] + this[2] * b[2] + this[3] * b[3]
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Returns whether two quaternions represent the same rotation
|
|
594
|
+
*
|
|
595
|
+
* @param {Quat} b the second operand
|
|
596
|
+
* @returns {Boolean} true if the quaternions represent the same rotation
|
|
597
|
+
*/
|
|
598
|
+
equals(b: Quat) {
|
|
599
|
+
return Math.abs(Quat.dot(this, b)) >= 1 - glm.EPSILON
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
private static tmpVec3 = vec3()
|
|
603
|
+
/**
|
|
604
|
+
* Sets a quaternion to represent the shortest rotation from one vector to another
|
|
605
|
+
*
|
|
606
|
+
* @param {Vec3} a the initial vector
|
|
607
|
+
* @param {Vec3} b the destination vector
|
|
608
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
609
|
+
* @returns {Quat} out
|
|
610
|
+
*/
|
|
611
|
+
static rotationTo(a: Vec3, b: Vec3, out = quat()): Quat {
|
|
612
|
+
const dot = vec3.dot(a, b)
|
|
613
|
+
if (dot < -0.999999) {
|
|
614
|
+
vec3.cross(vec3.unitX, a, Quat.tmpVec3)
|
|
615
|
+
if (Quat.tmpVec3.len() < 0.000001)
|
|
616
|
+
vec3.cross(vec3.unitY, a, Quat.tmpVec3)
|
|
617
|
+
return this.fromAxisAngle(Quat.tmpVec3.normalize(), Math.PI, out)
|
|
618
|
+
} else if (dot > 0.999999) {
|
|
619
|
+
out[0] = out[1] = out[2] = 0
|
|
620
|
+
out[3] = 1
|
|
621
|
+
return out
|
|
622
|
+
} else {
|
|
623
|
+
vec3.cross(a, b, Quat.tmpVec3)
|
|
624
|
+
out[0] = Quat.tmpVec3[0]
|
|
625
|
+
out[1] = Quat.tmpVec3[1]
|
|
626
|
+
out[2] = Quat.tmpVec3[2]
|
|
627
|
+
out[3] = 1 + dot
|
|
628
|
+
return out.normalize(out)
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
private static tmp1 = new Quat()
|
|
633
|
+
private static tmp2 = new Quat()
|
|
634
|
+
/**
|
|
635
|
+
* Performs a spherical linear interpolation with two control points
|
|
636
|
+
*
|
|
637
|
+
* @param {Quat} a the first operand
|
|
638
|
+
* @param {Quat} b the second operand
|
|
639
|
+
* @param {Quat} c the third operand
|
|
640
|
+
* @param {Quat} d the fourth operand
|
|
641
|
+
* @param {Number} t interpolation amount, in the range [0-1], between the two inputs
|
|
642
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
643
|
+
* @returns {Quat} out
|
|
644
|
+
*/
|
|
645
|
+
static sqlerp(a: Quat, b: Quat, c: Quat, d: Quat, t: number, out = quat()): Quat {
|
|
646
|
+
Quat.slerp(a, d, t, Quat.tmp1)
|
|
647
|
+
Quat.slerp(b, c, t, Quat.tmp2)
|
|
648
|
+
Quat.slerp(Quat.tmp1, Quat.tmp2, 2 * t * (1 - t), out)
|
|
649
|
+
return out
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
private static tmpMat3 = new Mat3()
|
|
653
|
+
/**
|
|
654
|
+
* Sets the specified quaternion with values corresponding to the given axes
|
|
655
|
+
*
|
|
656
|
+
* @param {Vec3} view the vector representing the viewing direction
|
|
657
|
+
* @param {Vec3} right the vector representing the local right direction
|
|
658
|
+
* @param {Vec3} up the vector representing the local up direction
|
|
659
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
660
|
+
* @returns {Quat} out
|
|
661
|
+
*/
|
|
662
|
+
static setAxes(view: Vec3, right: Vec3, up: Vec3, out = quat()) {
|
|
663
|
+
Quat.tmpMat3[0] = right[0]
|
|
664
|
+
Quat.tmpMat3[3] = right[1]
|
|
665
|
+
Quat.tmpMat3[6] = right[2]
|
|
666
|
+
|
|
667
|
+
Quat.tmpMat3[1] = up[0]
|
|
668
|
+
Quat.tmpMat3[4] = up[1]
|
|
669
|
+
Quat.tmpMat3[7] = up[2]
|
|
670
|
+
|
|
671
|
+
const vs = glm.LEFT_HANDED ? 1 : -1
|
|
672
|
+
Quat.tmpMat3[2] = vs * view[0]
|
|
673
|
+
Quat.tmpMat3[5] = vs * view[1]
|
|
674
|
+
Quat.tmpMat3[8] = vs * view[2]
|
|
675
|
+
|
|
676
|
+
return Quat.fromMat3(Quat.tmpMat3, out).normalize()
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Normalizes a quaternion
|
|
681
|
+
*
|
|
682
|
+
* @param {Quat} out the receiving vector, defaults to this
|
|
683
|
+
* @returns {Quat} out
|
|
684
|
+
*/
|
|
685
|
+
normalize(out = glm.ALWAYS_COPY ? new Quat() : this): Quat {
|
|
686
|
+
const x = this[0], y = this[1], z = this[2], w = this[3]
|
|
687
|
+
let len = x * x + y * y + z * z + w * w
|
|
688
|
+
if (len > 0) {
|
|
689
|
+
len = 1.0 / Math.sqrt(len)
|
|
690
|
+
}
|
|
691
|
+
out[0] = x * len
|
|
692
|
+
out[1] = y * len
|
|
693
|
+
out[2] = z * len
|
|
694
|
+
out[3] = w * len
|
|
695
|
+
return out
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Creates a quaternion that looks along the given direction vector
|
|
700
|
+
*
|
|
701
|
+
* @param {Vec3} direction the direction to look along
|
|
702
|
+
* @param {Vec3} up the up vector
|
|
703
|
+
* @param {Quat} out the receiving quaternion, defaults to quat()
|
|
704
|
+
* @returns {Quat} out
|
|
705
|
+
*/
|
|
706
|
+
static quatLookAt(direction: Vec3, up: Vec3, out = new Quat()): Quat {
|
|
707
|
+
const f = vec3(direction[0], direction[1], direction[2]).normalize()
|
|
708
|
+
const s = Vec3.cross(f, up).normalize()
|
|
709
|
+
const u = Vec3.cross(s, f)
|
|
710
|
+
const m = new Mat3()
|
|
711
|
+
const vs = glm.LEFT_HANDED ? 1 : -1
|
|
712
|
+
m[0] = s[0]; m[1] = u[0]; m[2] = vs * f[0]
|
|
713
|
+
m[3] = s[1]; m[4] = u[1]; m[5] = vs * f[1]
|
|
714
|
+
m[6] = s[2]; m[7] = u[2]; m[8] = vs * f[2]
|
|
715
|
+
return Quat.fromMat3(m, out)
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Extracts the pitch (rotation around X axis) from a quaternion
|
|
720
|
+
*
|
|
721
|
+
* @returns {Number} pitch in radians
|
|
722
|
+
*/
|
|
723
|
+
pitch(): number {
|
|
724
|
+
const x = this[0], y = this[1], z = this[2], w = this[3]
|
|
725
|
+
return Math.atan2(2 * (y * z + w * x), w * w - x * x - y * y + z * z)
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* Extracts the yaw (rotation around Y axis) from a quaternion
|
|
730
|
+
*
|
|
731
|
+
* @returns {Number} yaw in radians
|
|
732
|
+
*/
|
|
733
|
+
yaw(): number {
|
|
734
|
+
return Math.asin(Math.min(Math.max(-2 * (this[0] * this[2] - this[3] * this[1]), -1), 1))
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/**
|
|
738
|
+
* Extracts the roll (rotation around Z axis) from a quaternion
|
|
739
|
+
*
|
|
740
|
+
* @returns {Number} roll in radians
|
|
741
|
+
*/
|
|
742
|
+
roll(): number {
|
|
743
|
+
const x = this[0], y = this[1], z = this[2], w = this[3]
|
|
744
|
+
return Math.atan2(2 * (x * y + w * z), w * w + x * x - y * y - z * z)
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Extracts Euler angles (pitch, yaw, roll) from a quaternion
|
|
749
|
+
*
|
|
750
|
+
* @param {Vec3} out the receiving vector, defaults to vec3()
|
|
751
|
+
* @returns {Vec3} out with [pitch, yaw, roll] in radians
|
|
752
|
+
*/
|
|
753
|
+
eulerAngles(out = new Vec3()): Vec3 {
|
|
754
|
+
out[0] = this.pitch()
|
|
755
|
+
out[1] = this.yaw()
|
|
756
|
+
out[2] = this.roll()
|
|
757
|
+
return out
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* Converts a quaternion to a 3x3 rotation matrix
|
|
762
|
+
*
|
|
763
|
+
* @param {Mat3} out the receiving matrix, defaults to mat3()
|
|
764
|
+
* @returns {Mat3} out
|
|
765
|
+
*/
|
|
766
|
+
toMat3(out = new Mat3()): Mat3 {
|
|
767
|
+
const x = this[0], y = this[1], z = this[2], w = this[3]
|
|
768
|
+
const x2 = x + x, y2 = y + y, z2 = z + z
|
|
769
|
+
const xx = x * x2, xy = x * y2, xz = x * z2
|
|
770
|
+
const yy = y * y2, yz = y * z2, zz = z * z2
|
|
771
|
+
const wx = w * x2, wy = w * y2, wz = w * z2
|
|
772
|
+
out[0] = 1 - (yy + zz); out[1] = xy + wz; out[2] = xz - wy
|
|
773
|
+
out[3] = xy - wz; out[4] = 1 - (xx + zz); out[5] = yz + wx
|
|
774
|
+
out[6] = xz + wy; out[7] = yz - wx; out[8] = 1 - (xx + yy)
|
|
775
|
+
return out
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Converts a quaternion to a 4x4 rotation matrix
|
|
780
|
+
*
|
|
781
|
+
* @param {Mat4} out the receiving matrix, defaults to mat4()
|
|
782
|
+
* @returns {Mat4} out
|
|
783
|
+
*/
|
|
784
|
+
toMat4(out = new Mat4()): Mat4 {
|
|
785
|
+
const x = this[0], y = this[1], z = this[2], w = this[3]
|
|
786
|
+
const x2 = x + x, y2 = y + y, z2 = z + z
|
|
787
|
+
const xx = x * x2, xy = x * y2, xz = x * z2
|
|
788
|
+
const yy = y * y2, yz = y * z2, zz = z * z2
|
|
789
|
+
const wx = w * x2, wy = w * y2, wz = w * z2
|
|
790
|
+
out[0] = 1 - (yy + zz); out[1] = xy + wz; out[2] = xz - wy; out[3] = 0
|
|
791
|
+
out[4] = xy - wz; out[5] = 1 - (xx + zz); out[6] = yz + wx; out[7] = 0
|
|
792
|
+
out[8] = xz + wy; out[9] = yz - wx; out[10] = 1 - (xx + yy); out[11] = 0
|
|
793
|
+
out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1
|
|
794
|
+
return out
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
// @ts-ignore
|
|
799
|
+
export interface Quat {
|
|
800
|
+
multiply: (b: Quat | number, out?: Quat) => Quat
|
|
801
|
+
mult: (b: Quat | number, out?: Quat) => Quat
|
|
802
|
+
mul: (b: Quat | number, out?: Quat) => Quat
|
|
803
|
+
scale: (b: Quat | number, out?: Quat) => Quat
|
|
804
|
+
times: (b: Quat | number, out?: Quat) => Quat
|
|
805
|
+
str: () => string
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// @aliases
|
|
809
|
+
Quat.getAngle = Quat.angle
|
|
810
|
+
Quat.prototype.mult = Quat.prototype.multiply
|
|
811
|
+
Quat.prototype.mul = Quat.prototype.multiply
|
|
812
|
+
Quat.prototype.scale = Quat.prototype.multiply
|
|
813
|
+
Quat.prototype.times = Quat.prototype.multiply
|
|
814
|
+
Quat.prototype.str = Quat.prototype.toString
|
|
815
|
+
|
|
816
|
+
export const quat = Object.assign(
|
|
817
|
+
(x = 0, y = 0, z = 0, w = 1) => new Quat(x, y, z, w),
|
|
818
|
+
Quat
|
|
819
|
+
)
|