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
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
import { describe, it } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import glmaths, { Vec3, vec3, Mat3, Mat4, Quat } from '../dist/esm/glmaths'
|
|
4
|
+
|
|
5
|
+
function closeTo(actual: number, expected: number, numDigits = 5) {
|
|
6
|
+
const pass = Math.abs(actual - expected) < Math.pow(10, -numDigits) / 2
|
|
7
|
+
assert.ok(pass, `expected ${actual} to be close to ${expected}`)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const EPSILON = glmaths.EPSILON
|
|
11
|
+
|
|
12
|
+
describe('Vec3', () => {
|
|
13
|
+
describe('constructor', () => {
|
|
14
|
+
it('creates a zero vector by default', () => {
|
|
15
|
+
const v = new Vec3()
|
|
16
|
+
assert.strictEqual(v[0], 0)
|
|
17
|
+
assert.strictEqual(v[1], 0)
|
|
18
|
+
assert.strictEqual(v[2], 0)
|
|
19
|
+
})
|
|
20
|
+
it('creates with given values', () => {
|
|
21
|
+
const v = new Vec3(1, 2, 3)
|
|
22
|
+
assert.strictEqual(v[0], 1)
|
|
23
|
+
assert.strictEqual(v[1], 2)
|
|
24
|
+
assert.strictEqual(v[2], 3)
|
|
25
|
+
})
|
|
26
|
+
it('extends Float32Array with length 3', () => {
|
|
27
|
+
const v = new Vec3()
|
|
28
|
+
assert.ok(v instanceof Float32Array)
|
|
29
|
+
assert.strictEqual(v.length, 3)
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('x/y/z getters and setters', () => {
|
|
34
|
+
it('gets and sets correctly', () => {
|
|
35
|
+
const v = new Vec3()
|
|
36
|
+
v.x = 1; v.y = 2; v.z = 3
|
|
37
|
+
assert.strictEqual(v.x, 1)
|
|
38
|
+
assert.strictEqual(v.y, 2)
|
|
39
|
+
assert.strictEqual(v.z, 3)
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
describe('static constants', () => {
|
|
44
|
+
it('ZERO', () => {
|
|
45
|
+
const v = Vec3.ZERO
|
|
46
|
+
assert.strictEqual(v[0], 0)
|
|
47
|
+
assert.strictEqual(v[1], 0)
|
|
48
|
+
assert.strictEqual(v[2], 0)
|
|
49
|
+
})
|
|
50
|
+
it('ONE', () => {
|
|
51
|
+
const v = Vec3.ONE
|
|
52
|
+
assert.strictEqual(v[0], 1)
|
|
53
|
+
assert.strictEqual(v[1], 1)
|
|
54
|
+
assert.strictEqual(v[2], 1)
|
|
55
|
+
})
|
|
56
|
+
it('unitX/Y/Z', () => {
|
|
57
|
+
assert.strictEqual(Vec3.unitX[0], 1)
|
|
58
|
+
assert.strictEqual(Vec3.unitX[1], 0)
|
|
59
|
+
assert.strictEqual(Vec3.unitY[1], 1)
|
|
60
|
+
assert.strictEqual(Vec3.unitZ[2], 1)
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('arithmetic', () => {
|
|
65
|
+
it('plus with vector', () => {
|
|
66
|
+
const a = new Vec3(1, 2, 3)
|
|
67
|
+
const b = new Vec3(4, 5, 6)
|
|
68
|
+
const out = new Vec3()
|
|
69
|
+
a.plus(b, out)
|
|
70
|
+
assert.strictEqual(out[0], 5)
|
|
71
|
+
assert.strictEqual(out[1], 7)
|
|
72
|
+
assert.strictEqual(out[2], 9)
|
|
73
|
+
})
|
|
74
|
+
it('plus with scalar', () => {
|
|
75
|
+
const a = new Vec3(1, 2, 3)
|
|
76
|
+
const r = a.plus(10)
|
|
77
|
+
assert.strictEqual(r[0], 11)
|
|
78
|
+
assert.strictEqual(r[1], 12)
|
|
79
|
+
assert.strictEqual(r[2], 13)
|
|
80
|
+
})
|
|
81
|
+
it('minus with vector', () => {
|
|
82
|
+
const a = new Vec3(5, 7, 9)
|
|
83
|
+
const b = new Vec3(1, 2, 3)
|
|
84
|
+
const out = new Vec3()
|
|
85
|
+
a.minus(b, out)
|
|
86
|
+
assert.strictEqual(out[0], 4)
|
|
87
|
+
assert.strictEqual(out[1], 5)
|
|
88
|
+
assert.strictEqual(out[2], 6)
|
|
89
|
+
})
|
|
90
|
+
it('mult with vector', () => {
|
|
91
|
+
const a = new Vec3(2, 3, 4)
|
|
92
|
+
const b = new Vec3(5, 6, 7)
|
|
93
|
+
const out = new Vec3()
|
|
94
|
+
a.mult(b, out)
|
|
95
|
+
assert.strictEqual(out[0], 10)
|
|
96
|
+
assert.strictEqual(out[1], 18)
|
|
97
|
+
assert.strictEqual(out[2], 28)
|
|
98
|
+
})
|
|
99
|
+
it('mult with scalar', () => {
|
|
100
|
+
const a = new Vec3(2, 3, 4)
|
|
101
|
+
const r = a.mult(3)
|
|
102
|
+
assert.strictEqual(r[0], 6)
|
|
103
|
+
assert.strictEqual(r[1], 9)
|
|
104
|
+
assert.strictEqual(r[2], 12)
|
|
105
|
+
})
|
|
106
|
+
it('div with vector', () => {
|
|
107
|
+
const a = new Vec3(10, 20, 30)
|
|
108
|
+
const b = new Vec3(2, 4, 5)
|
|
109
|
+
const out = new Vec3()
|
|
110
|
+
a.div(b, out)
|
|
111
|
+
assert.strictEqual(out[0], 5)
|
|
112
|
+
assert.strictEqual(out[1], 5)
|
|
113
|
+
assert.strictEqual(out[2], 6)
|
|
114
|
+
})
|
|
115
|
+
it('scale', () => {
|
|
116
|
+
const a = new Vec3(1, 2, 3)
|
|
117
|
+
const r = a.scale(2)
|
|
118
|
+
assert.strictEqual(r[0], 2)
|
|
119
|
+
assert.strictEqual(r[1], 4)
|
|
120
|
+
assert.strictEqual(r[2], 6)
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe('negate', () => {
|
|
125
|
+
it('negates components', () => {
|
|
126
|
+
const a = new Vec3(1, -2, 3)
|
|
127
|
+
const r = a.negate()
|
|
128
|
+
assert.strictEqual(r[0], -1)
|
|
129
|
+
assert.strictEqual(r[1], 2)
|
|
130
|
+
assert.strictEqual(r[2], -3)
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
describe('normalize', () => {
|
|
135
|
+
it('normalizes to unit length (instance)', () => {
|
|
136
|
+
const a = new Vec3(0, 3, 4)
|
|
137
|
+
const r = a.normalize()
|
|
138
|
+
closeTo(r.len(), 1)
|
|
139
|
+
closeTo(r[0], 0)
|
|
140
|
+
closeTo(r[1], 0.6)
|
|
141
|
+
closeTo(r[2], 0.8)
|
|
142
|
+
})
|
|
143
|
+
it('normalizes to unit length (static)', () => {
|
|
144
|
+
const v = new Vec3(0, 3, 4)
|
|
145
|
+
const out = Vec3.normalize(v)
|
|
146
|
+
closeTo(out.len(), 1)
|
|
147
|
+
})
|
|
148
|
+
it('handles zero vector', () => {
|
|
149
|
+
const a = new Vec3(0, 0, 0)
|
|
150
|
+
a.normalize()
|
|
151
|
+
assert.strictEqual(a[0], 0)
|
|
152
|
+
assert.strictEqual(a[1], 0)
|
|
153
|
+
assert.strictEqual(a[2], 0)
|
|
154
|
+
})
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
describe('len / squaredLength', () => {
|
|
158
|
+
it('calculates length', () => {
|
|
159
|
+
const a = new Vec3(1, 2, 2)
|
|
160
|
+
closeTo(a.len(), 3)
|
|
161
|
+
})
|
|
162
|
+
it('calculates squared length', () => {
|
|
163
|
+
const a = new Vec3(1, 2, 2)
|
|
164
|
+
assert.strictEqual(a.squaredLength(), 9)
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
describe('floor / round / ceil', () => {
|
|
169
|
+
it('static floor', () => {
|
|
170
|
+
const v = new Vec3(1.7, 2.3, 3.9)
|
|
171
|
+
const out = Vec3.floor(v)
|
|
172
|
+
assert.strictEqual(out[0], 1)
|
|
173
|
+
assert.strictEqual(out[1], 2)
|
|
174
|
+
assert.strictEqual(out[2], 3)
|
|
175
|
+
})
|
|
176
|
+
it('instance floor', () => {
|
|
177
|
+
const v = new Vec3(1.7, 2.3, 3.9)
|
|
178
|
+
const r = v.floor()
|
|
179
|
+
assert.strictEqual(r[0], 1)
|
|
180
|
+
assert.strictEqual(r[1], 2)
|
|
181
|
+
assert.strictEqual(r[2], 3)
|
|
182
|
+
})
|
|
183
|
+
it('static round', () => {
|
|
184
|
+
const v = new Vec3(1.4, 2.6, 3.5)
|
|
185
|
+
const out = Vec3.round(v)
|
|
186
|
+
assert.strictEqual(out[0], 1)
|
|
187
|
+
assert.strictEqual(out[1], 3)
|
|
188
|
+
assert.strictEqual(out[2], 4)
|
|
189
|
+
})
|
|
190
|
+
it('static ceil', () => {
|
|
191
|
+
const v = new Vec3(1.1, 2.0, 3.9)
|
|
192
|
+
const out = Vec3.ceil(v)
|
|
193
|
+
assert.strictEqual(out[0], 2)
|
|
194
|
+
assert.strictEqual(out[1], 2)
|
|
195
|
+
assert.strictEqual(out[2], 4)
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
describe('inverse', () => {
|
|
200
|
+
it('static inverse', () => {
|
|
201
|
+
const v = new Vec3(2, 4, 5)
|
|
202
|
+
const out = Vec3.inverse(v)
|
|
203
|
+
closeTo(out[0], 0.5)
|
|
204
|
+
closeTo(out[1], 0.25)
|
|
205
|
+
closeTo(out[2], 0.2)
|
|
206
|
+
})
|
|
207
|
+
it('instance inverse', () => {
|
|
208
|
+
const v = new Vec3(2, 4, 5)
|
|
209
|
+
const r = v.inverse()
|
|
210
|
+
closeTo(r[0], 0.5)
|
|
211
|
+
closeTo(r[1], 0.25)
|
|
212
|
+
closeTo(r[2], 0.2)
|
|
213
|
+
})
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
describe('clone / toString', () => {
|
|
217
|
+
it('clones correctly', () => {
|
|
218
|
+
const a = new Vec3(1, 2, 3)
|
|
219
|
+
const b = a.clone()
|
|
220
|
+
assert.strictEqual(b[0], 1)
|
|
221
|
+
assert.strictEqual(b[1], 2)
|
|
222
|
+
assert.strictEqual(b[2], 3)
|
|
223
|
+
b[0] = 99
|
|
224
|
+
assert.strictEqual(a[0], 1)
|
|
225
|
+
})
|
|
226
|
+
it('toString', () => {
|
|
227
|
+
assert.strictEqual(new Vec3(1, 2, 3).toString(), 'vec3(1, 2, 3)')
|
|
228
|
+
})
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
describe('equals / exactEquals', () => {
|
|
232
|
+
it('exactEquals', () => {
|
|
233
|
+
assert.strictEqual(new Vec3(1, 2, 3).exactEquals(new Vec3(1, 2, 3)), true)
|
|
234
|
+
assert.strictEqual(new Vec3(1, 2, 3).exactEquals(new Vec3(1, 2, 4)), false)
|
|
235
|
+
})
|
|
236
|
+
it('equals with epsilon', () => {
|
|
237
|
+
const a = new Vec3(1, 2, 3)
|
|
238
|
+
const b = new Vec3(1 + EPSILON * 0.1, 2, 3)
|
|
239
|
+
assert.strictEqual(a.equals(b), true)
|
|
240
|
+
})
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
describe('static dot', () => {
|
|
244
|
+
it('calculates dot product', () => {
|
|
245
|
+
const a = new Vec3(1, 2, 3)
|
|
246
|
+
const b = new Vec3(4, 5, 6)
|
|
247
|
+
assert.strictEqual(Vec3.dot(a, b), 32)
|
|
248
|
+
})
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
describe('static cross', () => {
|
|
252
|
+
it('calculates cross product', () => {
|
|
253
|
+
const a = new Vec3(1, 0, 0)
|
|
254
|
+
const b = new Vec3(0, 1, 0)
|
|
255
|
+
const out = Vec3.cross(a, b)
|
|
256
|
+
assert.strictEqual(out[0], 0)
|
|
257
|
+
assert.strictEqual(out[1], 0)
|
|
258
|
+
assert.strictEqual(out[2], 1)
|
|
259
|
+
})
|
|
260
|
+
it('cross product is anti-commutative', () => {
|
|
261
|
+
const a = new Vec3(1, 0, 0)
|
|
262
|
+
const b = new Vec3(0, 1, 0)
|
|
263
|
+
const ab = Vec3.cross(a, b)
|
|
264
|
+
const ba = Vec3.cross(b, a)
|
|
265
|
+
closeTo(ab[0], -ba[0])
|
|
266
|
+
closeTo(ab[1], -ba[1])
|
|
267
|
+
closeTo(ab[2], -ba[2])
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
describe('static distance / squaredDistance', () => {
|
|
272
|
+
it('distance', () => {
|
|
273
|
+
const a = new Vec3(0, 0, 0)
|
|
274
|
+
const b = new Vec3(1, 2, 2)
|
|
275
|
+
closeTo(Vec3.distance(a, b), 3)
|
|
276
|
+
})
|
|
277
|
+
it('squaredDistance', () => {
|
|
278
|
+
const a = new Vec3(0, 0, 0)
|
|
279
|
+
const b = new Vec3(1, 2, 2)
|
|
280
|
+
assert.strictEqual(Vec3.squaredDistance(a, b), 9)
|
|
281
|
+
})
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
describe('static lerp', () => {
|
|
285
|
+
it('interpolates at t=0.5', () => {
|
|
286
|
+
const a = new Vec3(0, 0, 0)
|
|
287
|
+
const b = new Vec3(10, 20, 30)
|
|
288
|
+
const out = Vec3.lerp(a, b, 0.5)
|
|
289
|
+
assert.strictEqual(out[0], 5)
|
|
290
|
+
assert.strictEqual(out[1], 10)
|
|
291
|
+
assert.strictEqual(out[2], 15)
|
|
292
|
+
})
|
|
293
|
+
it('t=0 returns a', () => {
|
|
294
|
+
const out = Vec3.lerp(new Vec3(1, 2, 3), new Vec3(4, 5, 6), 0)
|
|
295
|
+
assert.strictEqual(out[0], 1)
|
|
296
|
+
assert.strictEqual(out[1], 2)
|
|
297
|
+
assert.strictEqual(out[2], 3)
|
|
298
|
+
})
|
|
299
|
+
it('t=1 returns b', () => {
|
|
300
|
+
const out = Vec3.lerp(new Vec3(1, 2, 3), new Vec3(4, 5, 6), 1)
|
|
301
|
+
assert.strictEqual(out[0], 4)
|
|
302
|
+
assert.strictEqual(out[1], 5)
|
|
303
|
+
assert.strictEqual(out[2], 6)
|
|
304
|
+
})
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
describe('static slerp', () => {
|
|
308
|
+
it('slerp at t=0 returns a', () => {
|
|
309
|
+
const a = new Vec3(1, 0, 0)
|
|
310
|
+
const b = new Vec3(0, 1, 0)
|
|
311
|
+
const out = Vec3.slerp(a, b, 0)
|
|
312
|
+
closeTo(out[0], 1)
|
|
313
|
+
closeTo(out[1], 0)
|
|
314
|
+
})
|
|
315
|
+
it('slerp at t=1 returns b', () => {
|
|
316
|
+
const a = new Vec3(1, 0, 0)
|
|
317
|
+
const b = new Vec3(0, 1, 0)
|
|
318
|
+
const out = Vec3.slerp(a, b, 1)
|
|
319
|
+
closeTo(out[0], 0)
|
|
320
|
+
closeTo(out[1], 1)
|
|
321
|
+
})
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
describe('static max / min', () => {
|
|
325
|
+
it('max', () => {
|
|
326
|
+
const out = Vec3.max(new Vec3(1, 5, 3), new Vec3(3, 2, 6))
|
|
327
|
+
assert.strictEqual(out[0], 3)
|
|
328
|
+
assert.strictEqual(out[1], 5)
|
|
329
|
+
assert.strictEqual(out[2], 6)
|
|
330
|
+
})
|
|
331
|
+
it('min', () => {
|
|
332
|
+
const out = Vec3.min(new Vec3(1, 5, 3), new Vec3(3, 2, 6))
|
|
333
|
+
assert.strictEqual(out[0], 1)
|
|
334
|
+
assert.strictEqual(out[1], 2)
|
|
335
|
+
assert.strictEqual(out[2], 3)
|
|
336
|
+
})
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
describe('static angle', () => {
|
|
340
|
+
it('90 degrees between orthogonal vectors', () => {
|
|
341
|
+
closeTo(Vec3.angle(new Vec3(1, 0, 0), new Vec3(0, 1, 0)), Math.PI / 2)
|
|
342
|
+
})
|
|
343
|
+
it('0 degrees between parallel vectors', () => {
|
|
344
|
+
closeTo(Vec3.angle(new Vec3(1, 0, 0), new Vec3(5, 0, 0)), 0)
|
|
345
|
+
})
|
|
346
|
+
it('180 degrees between opposite vectors', () => {
|
|
347
|
+
closeTo(Vec3.angle(new Vec3(1, 0, 0), new Vec3(-1, 0, 0)), Math.PI)
|
|
348
|
+
})
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
describe('rotateX / rotateY / rotateZ', () => {
|
|
352
|
+
it('rotateX by 90 degrees', () => {
|
|
353
|
+
const v = new Vec3(0, 1, 0)
|
|
354
|
+
const out = Vec3.rotateX(v, Math.PI / 2)
|
|
355
|
+
closeTo(out[0], 0)
|
|
356
|
+
closeTo(out[1], 0)
|
|
357
|
+
closeTo(out[2], 1)
|
|
358
|
+
})
|
|
359
|
+
it('rotateY by 90 degrees', () => {
|
|
360
|
+
const v = new Vec3(1, 0, 0)
|
|
361
|
+
const out = Vec3.rotateY(v, Math.PI / 2)
|
|
362
|
+
closeTo(out[0], 0)
|
|
363
|
+
closeTo(out[1], 0)
|
|
364
|
+
closeTo(out[2], -1)
|
|
365
|
+
})
|
|
366
|
+
it('rotateZ by 90 degrees', () => {
|
|
367
|
+
const v = new Vec3(1, 0, 0)
|
|
368
|
+
const out = Vec3.rotateZ(v, Math.PI / 2)
|
|
369
|
+
closeTo(out[0], 0)
|
|
370
|
+
closeTo(out[1], 1)
|
|
371
|
+
closeTo(out[2], 0)
|
|
372
|
+
})
|
|
373
|
+
it('rotateZ preserves z component', () => {
|
|
374
|
+
const v = new Vec3(1, 0, 5)
|
|
375
|
+
const out = Vec3.rotateZ(v, Math.PI / 2)
|
|
376
|
+
closeTo(out[2], 5)
|
|
377
|
+
})
|
|
378
|
+
it('rotateX with origin', () => {
|
|
379
|
+
const v = new Vec3(0, 2, 0)
|
|
380
|
+
const origin = new Vec3(0, 1, 0)
|
|
381
|
+
const out = Vec3.rotateX(v, Math.PI / 2, origin)
|
|
382
|
+
closeTo(out[0], 0)
|
|
383
|
+
closeTo(out[1], 1)
|
|
384
|
+
closeTo(out[2], 1)
|
|
385
|
+
})
|
|
386
|
+
it('instance rotateX', () => {
|
|
387
|
+
const v = new Vec3(0, 1, 0)
|
|
388
|
+
const out = new Vec3()
|
|
389
|
+
v.rotateX(Math.PI / 2, Vec3.zero, out)
|
|
390
|
+
closeTo(out[0], 0)
|
|
391
|
+
closeTo(out[1], 0)
|
|
392
|
+
closeTo(out[2], 1)
|
|
393
|
+
})
|
|
394
|
+
it('instance rotateZ', () => {
|
|
395
|
+
const v = new Vec3(1, 0, 0)
|
|
396
|
+
const out = new Vec3()
|
|
397
|
+
v.rotateZ(Math.PI / 2, Vec3.zero, out)
|
|
398
|
+
closeTo(out[0], 0)
|
|
399
|
+
closeTo(out[1], 1)
|
|
400
|
+
closeTo(out[2], 0)
|
|
401
|
+
})
|
|
402
|
+
it('rotateZ with non-zero origin', () => {
|
|
403
|
+
const v = new Vec3(2, 0, 0)
|
|
404
|
+
const origin = new Vec3(1, 0, 0)
|
|
405
|
+
const out = Vec3.rotateZ(v, Math.PI / 2, origin)
|
|
406
|
+
closeTo(out[0], 1)
|
|
407
|
+
closeTo(out[1], 1)
|
|
408
|
+
closeTo(out[2], 0)
|
|
409
|
+
})
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
describe('factory function', () => {
|
|
413
|
+
it('vec3() creates Vec3', () => {
|
|
414
|
+
const v = vec3(1, 2, 3)
|
|
415
|
+
assert.ok(v instanceof Vec3)
|
|
416
|
+
assert.strictEqual(v[0], 1)
|
|
417
|
+
assert.strictEqual(v[1], 2)
|
|
418
|
+
assert.strictEqual(v[2], 3)
|
|
419
|
+
})
|
|
420
|
+
})
|
|
421
|
+
|
|
422
|
+
describe('scaleAndAdd', () => {
|
|
423
|
+
it('adds scaled vector', () => {
|
|
424
|
+
const a = new Vec3(1, 2, 3)
|
|
425
|
+
const b = new Vec3(4, 5, 6)
|
|
426
|
+
const out = new Vec3()
|
|
427
|
+
a.scaleAndAdd(b, 2, out)
|
|
428
|
+
closeTo(out[0], 9)
|
|
429
|
+
closeTo(out[1], 12)
|
|
430
|
+
closeTo(out[2], 15)
|
|
431
|
+
})
|
|
432
|
+
it('static version', () => {
|
|
433
|
+
const out = Vec3.scaleAndAdd(new Vec3(1, 2, 3), new Vec3(1, 1, 1), 3)
|
|
434
|
+
closeTo(out[0], 4)
|
|
435
|
+
closeTo(out[1], 5)
|
|
436
|
+
closeTo(out[2], 6)
|
|
437
|
+
})
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
describe('abs', () => {
|
|
441
|
+
it('absolute value of components', () => {
|
|
442
|
+
const v = new Vec3(-1, -2, -3)
|
|
443
|
+
const out = new Vec3()
|
|
444
|
+
v.abs(out)
|
|
445
|
+
assert.strictEqual(out[0], 1)
|
|
446
|
+
assert.strictEqual(out[1], 2)
|
|
447
|
+
assert.strictEqual(out[2], 3)
|
|
448
|
+
})
|
|
449
|
+
})
|
|
450
|
+
|
|
451
|
+
describe('transformMat3', () => {
|
|
452
|
+
it('transforms by 3x3 rotation matrix', () => {
|
|
453
|
+
const v = new Vec3(1, 0, 0)
|
|
454
|
+
const m = Mat3.identity
|
|
455
|
+
const out = new Vec3()
|
|
456
|
+
v.transformMat3(m, out)
|
|
457
|
+
closeTo(out[0], 1)
|
|
458
|
+
closeTo(out[1], 0)
|
|
459
|
+
closeTo(out[2], 0)
|
|
460
|
+
})
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
describe('transformMat4', () => {
|
|
464
|
+
it('transforms by translation matrix', () => {
|
|
465
|
+
const v = new Vec3(1, 2, 3)
|
|
466
|
+
const m = Mat4.fromTranslation(new Vec3(10, 20, 30))
|
|
467
|
+
const out = new Vec3()
|
|
468
|
+
v.transformMat4(m, out)
|
|
469
|
+
closeTo(out[0], 11)
|
|
470
|
+
closeTo(out[1], 22)
|
|
471
|
+
closeTo(out[2], 33)
|
|
472
|
+
})
|
|
473
|
+
it('transforms by identity', () => {
|
|
474
|
+
const v = new Vec3(1, 2, 3)
|
|
475
|
+
const out = new Vec3()
|
|
476
|
+
v.transformMat4(Mat4.identity, out)
|
|
477
|
+
closeTo(out[0], 1)
|
|
478
|
+
closeTo(out[1], 2)
|
|
479
|
+
closeTo(out[2], 3)
|
|
480
|
+
})
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
describe('transformQuat', () => {
|
|
484
|
+
it('identity quat leaves vector unchanged', () => {
|
|
485
|
+
const v = new Vec3(1, 2, 3)
|
|
486
|
+
const q = Quat.identity
|
|
487
|
+
const out = new Vec3()
|
|
488
|
+
v.transformQuat(q, out)
|
|
489
|
+
closeTo(out[0], 1)
|
|
490
|
+
closeTo(out[1], 2)
|
|
491
|
+
closeTo(out[2], 3)
|
|
492
|
+
})
|
|
493
|
+
it('90 degree rotation around Y', () => {
|
|
494
|
+
const v = new Vec3(1, 0, 0)
|
|
495
|
+
const q = Quat.fromAxisAngle(new Vec3(0, 1, 0), Math.PI / 2)
|
|
496
|
+
const out = new Vec3()
|
|
497
|
+
v.transformQuat(q, out)
|
|
498
|
+
closeTo(out[0], 0)
|
|
499
|
+
closeTo(out[1], 0)
|
|
500
|
+
closeTo(out[2], -1)
|
|
501
|
+
})
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
describe('reflect', () => {
|
|
505
|
+
it('reflects off a surface', () => {
|
|
506
|
+
const I = new Vec3(1, -1, 0)
|
|
507
|
+
const N = new Vec3(0, 1, 0)
|
|
508
|
+
const out = Vec3.reflect(I, N)
|
|
509
|
+
closeTo(out[0], 1)
|
|
510
|
+
closeTo(out[1], 1)
|
|
511
|
+
closeTo(out[2], 0)
|
|
512
|
+
})
|
|
513
|
+
})
|
|
514
|
+
|
|
515
|
+
describe('refract', () => {
|
|
516
|
+
it('refracts through a surface', () => {
|
|
517
|
+
const I = new Vec3(0, -1, 0).normalize()
|
|
518
|
+
const N = new Vec3(0, 1, 0)
|
|
519
|
+
const out = Vec3.refract(I, N, 1.0)
|
|
520
|
+
closeTo(out[0], 0)
|
|
521
|
+
closeTo(out[1], -1)
|
|
522
|
+
closeTo(out[2], 0)
|
|
523
|
+
})
|
|
524
|
+
it('total internal reflection returns zero', () => {
|
|
525
|
+
const I = new Vec3(1, 0, 0).normalize()
|
|
526
|
+
const N = new Vec3(0, 1, 0)
|
|
527
|
+
const out = Vec3.refract(I, N, 1.5)
|
|
528
|
+
closeTo(out[0], 0)
|
|
529
|
+
closeTo(out[1], 0)
|
|
530
|
+
closeTo(out[2], 0)
|
|
531
|
+
})
|
|
532
|
+
})
|
|
533
|
+
|
|
534
|
+
describe('faceforward', () => {
|
|
535
|
+
it('flips normal when facing away from incident', () => {
|
|
536
|
+
const N = new Vec3(0, 1, 0)
|
|
537
|
+
const I = new Vec3(0, 1, 0)
|
|
538
|
+
const Nref = new Vec3(0, 1, 0)
|
|
539
|
+
const out = Vec3.faceforward(N, I, Nref)
|
|
540
|
+
assert.strictEqual(out[1], -1) // flipped because dot(Nref, I) > 0
|
|
541
|
+
})
|
|
542
|
+
it('keeps normal when facing incident', () => {
|
|
543
|
+
const N = new Vec3(0, 1, 0)
|
|
544
|
+
const I = new Vec3(0, -1, 0)
|
|
545
|
+
const Nref = new Vec3(0, 1, 0)
|
|
546
|
+
const out = Vec3.faceforward(N, I, Nref)
|
|
547
|
+
assert.strictEqual(out[1], 1)
|
|
548
|
+
})
|
|
549
|
+
})
|
|
550
|
+
|
|
551
|
+
describe('triangleNormal', () => {
|
|
552
|
+
it('computes normal of XY triangle', () => {
|
|
553
|
+
const p1 = new Vec3(0, 0, 0)
|
|
554
|
+
const p2 = new Vec3(1, 0, 0)
|
|
555
|
+
const p3 = new Vec3(0, 1, 0)
|
|
556
|
+
const out = Vec3.triangleNormal(p1, p2, p3)
|
|
557
|
+
closeTo(out[0], 0)
|
|
558
|
+
closeTo(out[1], 0)
|
|
559
|
+
closeTo(out[2], 1)
|
|
560
|
+
})
|
|
561
|
+
})
|
|
562
|
+
|
|
563
|
+
describe('project', () => {
|
|
564
|
+
it('projects vector onto another', () => {
|
|
565
|
+
const a = new Vec3(3, 4, 0)
|
|
566
|
+
const b = new Vec3(1, 0, 0)
|
|
567
|
+
const out = Vec3.project(a, b)
|
|
568
|
+
closeTo(out[0], 3)
|
|
569
|
+
closeTo(out[1], 0)
|
|
570
|
+
closeTo(out[2], 0)
|
|
571
|
+
})
|
|
572
|
+
})
|
|
573
|
+
|
|
574
|
+
describe('orientedAngle', () => {
|
|
575
|
+
it('positive angle for CCW rotation', () => {
|
|
576
|
+
const a = new Vec3(1, 0, 0)
|
|
577
|
+
const b = new Vec3(0, 1, 0)
|
|
578
|
+
const ref = new Vec3(0, 0, 1)
|
|
579
|
+
const angle = Vec3.orientedAngle(a, b, ref)
|
|
580
|
+
closeTo(angle, Math.PI / 2)
|
|
581
|
+
})
|
|
582
|
+
})
|
|
583
|
+
|
|
584
|
+
describe('GLSL functions', () => {
|
|
585
|
+
it('clamp with scalar', () => {
|
|
586
|
+
const v = new Vec3(-1, 0.5, 2)
|
|
587
|
+
const out = new Vec3()
|
|
588
|
+
v.clamp(0, 1, out)
|
|
589
|
+
assert.strictEqual(out[0], 0)
|
|
590
|
+
closeTo(out[1], 0.5)
|
|
591
|
+
assert.strictEqual(out[2], 1)
|
|
592
|
+
})
|
|
593
|
+
it('static clamp', () => {
|
|
594
|
+
const out = Vec3.clamp(new Vec3(-1, 0.5, 2), 0, 1)
|
|
595
|
+
assert.strictEqual(out[0], 0)
|
|
596
|
+
closeTo(out[1], 0.5)
|
|
597
|
+
assert.strictEqual(out[2], 1)
|
|
598
|
+
})
|
|
599
|
+
it('mix', () => {
|
|
600
|
+
const a = new Vec3(0, 0, 0)
|
|
601
|
+
const b = new Vec3(10, 20, 30)
|
|
602
|
+
const out = new Vec3()
|
|
603
|
+
a.mix(b, 0.5, out)
|
|
604
|
+
closeTo(out[0], 5)
|
|
605
|
+
closeTo(out[1], 10)
|
|
606
|
+
closeTo(out[2], 15)
|
|
607
|
+
})
|
|
608
|
+
it('step', () => {
|
|
609
|
+
const v = new Vec3(0.3, 0.5, 0.7)
|
|
610
|
+
const out = new Vec3()
|
|
611
|
+
v.step(0.5, out)
|
|
612
|
+
assert.strictEqual(out[0], 0)
|
|
613
|
+
assert.strictEqual(out[1], 1)
|
|
614
|
+
assert.strictEqual(out[2], 1)
|
|
615
|
+
})
|
|
616
|
+
it('smoothstep', () => {
|
|
617
|
+
const v = new Vec3(0, 0.5, 1)
|
|
618
|
+
const out = new Vec3()
|
|
619
|
+
v.smoothstep(0, 1, out)
|
|
620
|
+
closeTo(out[0], 0)
|
|
621
|
+
closeTo(out[1], 0.5)
|
|
622
|
+
closeTo(out[2], 1)
|
|
623
|
+
})
|
|
624
|
+
it('fract', () => {
|
|
625
|
+
const v = new Vec3(1.7, 2.3, 3.9)
|
|
626
|
+
const out = new Vec3()
|
|
627
|
+
v.fract(out)
|
|
628
|
+
closeTo(out[0], 0.7)
|
|
629
|
+
closeTo(out[1], 0.3)
|
|
630
|
+
closeTo(out[2], 0.9)
|
|
631
|
+
})
|
|
632
|
+
it('sign', () => {
|
|
633
|
+
const v = new Vec3(-5, 0, 3)
|
|
634
|
+
const out = new Vec3()
|
|
635
|
+
v.sign(out)
|
|
636
|
+
assert.strictEqual(out[0], -1)
|
|
637
|
+
assert.strictEqual(out[1], 0)
|
|
638
|
+
assert.strictEqual(out[2], 1)
|
|
639
|
+
})
|
|
640
|
+
it('saturate', () => {
|
|
641
|
+
const v = new Vec3(-0.5, 0.5, 1.5)
|
|
642
|
+
const out = new Vec3()
|
|
643
|
+
v.saturate(out)
|
|
644
|
+
assert.strictEqual(out[0], 0)
|
|
645
|
+
closeTo(out[1], 0.5)
|
|
646
|
+
assert.strictEqual(out[2], 1)
|
|
647
|
+
})
|
|
648
|
+
})
|
|
649
|
+
})
|