@nakednous/tree 0.0.12 → 0.0.14
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 +44 -20
- package/dist/index.js +427 -585
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -238,23 +238,27 @@ const quatToAxisAngle = (q, out) => {
|
|
|
238
238
|
* from specs requires only scalar arithmetic and quaternion conversions.
|
|
239
239
|
* Callers compose the resulting matrices using query.js (mat4Mul etc.).
|
|
240
240
|
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
241
|
+
* ── NDC Z convention ──────────────────────────────────────────────────────
|
|
242
|
+
* Controlled by `ndcZMin` in every projection constructor:
|
|
243
|
+
* WEBGL = −1 near → NDC z = −1, far → NDC z = +1
|
|
244
|
+
* WEBGPU = 0 near → NDC z = 0, far → NDC z = +1
|
|
245
|
+
*
|
|
246
|
+
* ── NDC Y convention ──────────────────────────────────────────────────────
|
|
247
|
+
* Controlled by `ndcYSign` in every projection constructor (default +1):
|
|
248
|
+
* +1 NDC y-up — standard: OpenGL / WebGL / WebGPU browser / Three.js / p5v2
|
|
249
|
+
* −1 NDC y-down — native Vulkan clip space
|
|
250
|
+
*
|
|
251
|
+
* Negating ndcYSign flips row 1 of the projection matrix (elements
|
|
252
|
+
* out[1], out[5], out[9], out[13]), reversing the y-axis in clip space.
|
|
253
|
+
* mat4View, mat4Eye, and all non-projection constructors are convention-
|
|
254
|
+
* agnostic — they produce the same matrix regardless of the NDC y direction.
|
|
255
|
+
*
|
|
256
|
+
* ── Screen Y convention ───────────────────────────────────────────────────
|
|
257
|
+
* Screen-y direction (DOM y-down vs OpenGL y-up) is a separate concern from
|
|
258
|
+
* NDC-y direction and is handled in query.js via the signed viewport height.
|
|
259
|
+
* See the query.js module header for details.
|
|
255
260
|
*
|
|
256
261
|
* All functions follow the out-first, zero-allocation contract.
|
|
257
|
-
* Returns null on degeneracy where applicable.
|
|
258
262
|
*/
|
|
259
263
|
|
|
260
264
|
|
|
@@ -264,8 +268,6 @@ const quatToAxisAngle = (q, out) => {
|
|
|
264
268
|
|
|
265
269
|
/**
|
|
266
270
|
* Rigid frame from orthonormal basis + translation.
|
|
267
|
-
* The primitive that lookat constructors use internally.
|
|
268
|
-
*
|
|
269
271
|
* Column-major layout: col0=right, col1=up, col2=forward, col3=translation.
|
|
270
272
|
*
|
|
271
273
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
@@ -273,7 +275,6 @@ const quatToAxisAngle = (q, out) => {
|
|
|
273
275
|
* @param {number} ux,uy,uz Up vector (col 1).
|
|
274
276
|
* @param {number} fx,fy,fz Forward vec (col 2).
|
|
275
277
|
* @param {number} tx,ty,tz Translation (col 3).
|
|
276
|
-
* @returns {Float32Array|number[]} out
|
|
277
278
|
*/
|
|
278
279
|
function mat4FromBasis(out, rx,ry,rz, ux,uy,uz, fx,fy,fz, tx,ty,tz) {
|
|
279
280
|
out[0]=rx; out[1]=ry; out[2]=rz; out[3]=0;
|
|
@@ -285,28 +286,22 @@ function mat4FromBasis(out, rx,ry,rz, ux,uy,uz, fx,fy,fz, tx,ty,tz) {
|
|
|
285
286
|
|
|
286
287
|
/**
|
|
287
288
|
* View matrix (world→eye) from lookat parameters.
|
|
289
|
+
* Camera looks along −Z in eye space; right = normalize(up × (−Z)).
|
|
288
290
|
* Cheaper than building the eye matrix and inverting.
|
|
289
291
|
*
|
|
290
|
-
* Convention: −Z axis points toward center (camera looks along −Z in eye space).
|
|
291
|
-
*
|
|
292
292
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
293
293
|
* @param {number} ex,ey,ez Eye (camera) position.
|
|
294
|
-
* @param {number} cx,cy,cz
|
|
294
|
+
* @param {number} cx,cy,cz Look-at target.
|
|
295
295
|
* @param {number} ux,uy,uz World up hint (need not be unit).
|
|
296
|
-
* @returns {Float32Array|number[]} out
|
|
297
296
|
*/
|
|
298
297
|
function mat4View(out, ex,ey,ez, cx,cy,cz, ux,uy,uz) {
|
|
299
|
-
// z = normalize(eye - center) (camera +Z away from target)
|
|
300
298
|
let zx=ex-cx, zy=ey-cy, zz=ez-cz;
|
|
301
299
|
const zl=Math.sqrt(zx*zx+zy*zy+zz*zz)||1;
|
|
302
300
|
zx/=zl; zy/=zl; zz/=zl;
|
|
303
|
-
// x = normalize(up × z) (right)
|
|
304
301
|
let xx=uy*zz-uz*zy, xy=uz*zx-ux*zz, xz=ux*zy-uy*zx;
|
|
305
302
|
const xl=Math.sqrt(xx*xx+xy*xy+xz*xz)||1;
|
|
306
303
|
xx/=xl; xy/=xl; xz/=xl;
|
|
307
|
-
// y = z × x (up_ortho, guaranteed perpendicular)
|
|
308
304
|
const yx=zy*xz-zz*xy, yy=zz*xx-zx*xz, yz=zx*xy-zy*xx;
|
|
309
|
-
// View = [R | -R·t] (column-major)
|
|
310
305
|
out[0]=xx; out[1]=yx; out[2]=zx; out[3]=0;
|
|
311
306
|
out[4]=xy; out[5]=yy; out[6]=zy; out[7]=0;
|
|
312
307
|
out[8]=xz; out[9]=yz; out[10]=zz; out[11]=0;
|
|
@@ -320,16 +315,14 @@ function mat4View(out, ex,ey,ez, cx,cy,cz, ux,uy,uz) {
|
|
|
320
315
|
/**
|
|
321
316
|
* Eye matrix (eye→world) from lookat parameters.
|
|
322
317
|
* Transpose of the rotation block + direct translation column.
|
|
323
|
-
* Same
|
|
318
|
+
* Same parameters as mat4View.
|
|
324
319
|
*
|
|
325
320
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
326
|
-
* @param {number} ex,ey,ez Eye
|
|
327
|
-
* @param {number} cx,cy,cz
|
|
328
|
-
* @param {number} ux,uy,uz World up hint
|
|
329
|
-
* @returns {Float32Array|number[]} out
|
|
321
|
+
* @param {number} ex,ey,ez Eye position.
|
|
322
|
+
* @param {number} cx,cy,cz Look-at target.
|
|
323
|
+
* @param {number} ux,uy,uz World up hint.
|
|
330
324
|
*/
|
|
331
325
|
function mat4Eye(out, ex,ey,ez, cx,cy,cz, ux,uy,uz) {
|
|
332
|
-
// Same basis computation as mat4View.
|
|
333
326
|
let zx=ex-cx, zy=ey-cy, zz=ez-cz;
|
|
334
327
|
const zl=Math.sqrt(zx*zx+zy*zy+zz*zz)||1;
|
|
335
328
|
zx/=zl; zy/=zl; zz/=zl;
|
|
@@ -337,7 +330,6 @@ function mat4Eye(out, ex,ey,ez, cx,cy,cz, ux,uy,uz) {
|
|
|
337
330
|
const xl=Math.sqrt(xx*xx+xy*xy+xz*xz)||1;
|
|
338
331
|
xx/=xl; xy/=xl; xz/=xl;
|
|
339
332
|
const yx=zy*xz-zz*xy, yy=zz*xx-zx*xz, yz=zx*xy-zy*xx;
|
|
340
|
-
// Eye matrix = [R^T | t] (rotation transposed, translation = eye position)
|
|
341
333
|
out[0]=xx; out[1]=xy; out[2]=xz; out[3]=0;
|
|
342
334
|
out[4]=yx; out[5]=yy; out[6]=yz; out[7]=0;
|
|
343
335
|
out[8]=zx; out[9]=zy; out[10]=zz; out[11]=0;
|
|
@@ -350,22 +342,20 @@ function mat4Eye(out, ex,ey,ez, cx,cy,cz, ux,uy,uz) {
|
|
|
350
342
|
// =========================================================================
|
|
351
343
|
|
|
352
344
|
/**
|
|
353
|
-
* Column-major mat4 from flat TRS scalars.
|
|
354
|
-
* No struct allocation — all components passed as plain numbers.
|
|
345
|
+
* Column-major mat4 from flat TRS scalars. No struct allocation.
|
|
355
346
|
*
|
|
356
347
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
357
348
|
* @param {number} tx,ty,tz Translation.
|
|
358
349
|
* @param {number} qx,qy,qz,qw Rotation quaternion [x,y,z,w].
|
|
359
350
|
* @param {number} sx,sy,sz Scale.
|
|
360
|
-
* @returns {Float32Array|number[]} out
|
|
361
351
|
*/
|
|
362
352
|
function mat4FromTRS(out, tx,ty,tz, qx,qy,qz,qw, sx,sy,sz) {
|
|
363
353
|
const x2=qx+qx,y2=qy+qy,z2=qz+qz;
|
|
364
354
|
const xx=qx*x2,xy=qx*y2,xz=qx*z2,yy=qy*y2,yz=qy*z2,zz=qz*z2;
|
|
365
355
|
const wx=qw*x2,wy=qw*y2,wz=qw*z2;
|
|
366
|
-
out[0]=(1-(yy+zz))*sx; out[1]=(xy+wz)*sx;
|
|
367
|
-
out[4]=(xy-wz)*sy; out[5]=(1-(xx+zz))*sy;
|
|
368
|
-
out[8]=(xz+wy)*sz; out[9]=(yz-wx)*sz;
|
|
356
|
+
out[0]=(1-(yy+zz))*sx; out[1]=(xy+wz)*sx; out[2]=(xz-wy)*sx; out[3]=0;
|
|
357
|
+
out[4]=(xy-wz)*sy; out[5]=(1-(xx+zz))*sy; out[6]=(yz+wx)*sy; out[7]=0;
|
|
358
|
+
out[8]=(xz+wy)*sz; out[9]=(yz-wx)*sz; out[10]=(1-(xx+yy))*sz; out[11]=0;
|
|
369
359
|
out[12]=tx; out[13]=ty; out[14]=tz; out[15]=1;
|
|
370
360
|
return out;
|
|
371
361
|
}
|
|
@@ -374,12 +364,11 @@ function mat4FromTRS(out, tx,ty,tz, qx,qy,qz,qw, sx,sy,sz) {
|
|
|
374
364
|
* Translation-only mat4.
|
|
375
365
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
376
366
|
* @param {number} tx,ty,tz
|
|
377
|
-
* @returns {Float32Array|number[]} out
|
|
378
367
|
*/
|
|
379
368
|
function mat4FromTranslation(out, tx,ty,tz) {
|
|
380
|
-
out[0]=1;
|
|
381
|
-
out[4]=0;
|
|
382
|
-
out[8]=0;
|
|
369
|
+
out[0]=1; out[1]=0; out[2]=0; out[3]=0;
|
|
370
|
+
out[4]=0; out[5]=1; out[6]=0; out[7]=0;
|
|
371
|
+
out[8]=0; out[9]=0; out[10]=1; out[11]=0;
|
|
383
372
|
out[12]=tx; out[13]=ty; out[14]=tz; out[15]=1;
|
|
384
373
|
return out;
|
|
385
374
|
}
|
|
@@ -388,11 +377,10 @@ function mat4FromTranslation(out, tx,ty,tz) {
|
|
|
388
377
|
* Scale-only mat4.
|
|
389
378
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
390
379
|
* @param {number} sx,sy,sz
|
|
391
|
-
* @returns {Float32Array|number[]} out
|
|
392
380
|
*/
|
|
393
381
|
function mat4FromScale(out, sx,sy,sz) {
|
|
394
|
-
out[0]=sx; out[1]=0; out[2]=0;
|
|
395
|
-
out[4]=0; out[5]=sy; out[6]=0;
|
|
382
|
+
out[0]=sx; out[1]=0; out[2]=0; out[3]=0;
|
|
383
|
+
out[4]=0; out[5]=sy; out[6]=0; out[7]=0;
|
|
396
384
|
out[8]=0; out[9]=0; out[10]=sz; out[11]=0;
|
|
397
385
|
out[12]=0; out[13]=0; out[14]=0; out[15]=1;
|
|
398
386
|
return out;
|
|
@@ -405,22 +393,19 @@ function mat4FromScale(out, sx,sy,sz) {
|
|
|
405
393
|
/**
|
|
406
394
|
* Perspective projection matrix.
|
|
407
395
|
*
|
|
408
|
-
* NDC convention: ndcZMin = WEBGL (−1) or WEBGPU (0).
|
|
409
|
-
* near maps to ndcZMin, far maps to +1.
|
|
410
|
-
*
|
|
411
396
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
412
|
-
* @param {number} fov
|
|
413
|
-
* @param {number} aspect
|
|
414
|
-
* @param {number} near
|
|
415
|
-
* @param {number} far
|
|
416
|
-
* @param {number} ndcZMin
|
|
417
|
-
* @
|
|
397
|
+
* @param {number} fov Vertical field of view (radians).
|
|
398
|
+
* @param {number} aspect Width / height.
|
|
399
|
+
* @param {number} near Near plane distance (positive).
|
|
400
|
+
* @param {number} far Far plane distance (positive, > near).
|
|
401
|
+
* @param {number} ndcZMin −1 (WEBGL) or 0 (WEBGPU).
|
|
402
|
+
* @param {number} [ndcYSign=1] +1 = NDC y-up (default); −1 = NDC y-down (native Vulkan).
|
|
418
403
|
*/
|
|
419
|
-
function mat4Perspective(out, fov, aspect, near, far, ndcZMin) {
|
|
404
|
+
function mat4Perspective(out, fov, aspect, near, far, ndcZMin, ndcYSign=1) {
|
|
420
405
|
const f = 1 / Math.tan(fov * 0.5);
|
|
421
|
-
out[0]=f/aspect;
|
|
422
|
-
out[4]=0;
|
|
423
|
-
out[8]=0;
|
|
406
|
+
out[0]=f/aspect; out[1]=0; out[2]=0; out[3]=0;
|
|
407
|
+
out[4]=0; out[5]=ndcYSign*f; out[6]=0; out[7]=0;
|
|
408
|
+
out[8]=0; out[9]=0;
|
|
424
409
|
out[10]=(ndcZMin*near-far)/(far-near);
|
|
425
410
|
out[11]=-1;
|
|
426
411
|
out[12]=0; out[13]=0;
|
|
@@ -432,22 +417,18 @@ function mat4Perspective(out, fov, aspect, near, far, ndcZMin) {
|
|
|
432
417
|
/**
|
|
433
418
|
* Orthographic projection matrix.
|
|
434
419
|
*
|
|
435
|
-
* NDC convention: ndcZMin = WEBGL (−1) or WEBGPU (0).
|
|
436
|
-
*
|
|
437
420
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
438
421
|
* @param {number} left,right,bottom,top Frustum extents.
|
|
439
422
|
* @param {number} near,far Clip plane distances (positive).
|
|
440
|
-
* @param {number} ndcZMin
|
|
441
|
-
* @
|
|
423
|
+
* @param {number} ndcZMin −1 (WEBGL) or 0 (WEBGPU).
|
|
424
|
+
* @param {number} [ndcYSign=1] +1 = NDC y-up (default); −1 = NDC y-down (native Vulkan).
|
|
442
425
|
*/
|
|
443
|
-
function mat4Ortho(out, left, right, bottom, top, near, far, ndcZMin) {
|
|
426
|
+
function mat4Ortho(out, left, right, bottom, top, near, far, ndcZMin, ndcYSign=1) {
|
|
444
427
|
const rl=1/(right-left), tb=1/(top-bottom), fn=1/(far-near);
|
|
445
|
-
out[0]=2*rl; out[1]=0;
|
|
446
|
-
out[4]=0; out[5]=2*tb;
|
|
447
|
-
out[8]=0; out[9]=0;
|
|
448
|
-
out[
|
|
449
|
-
out[11]=0;
|
|
450
|
-
out[12]=-(right+left)*rl; out[13]=-(top+bottom)*tb;
|
|
428
|
+
out[0]=2*rl; out[1]=0; out[2]=0; out[3]=0;
|
|
429
|
+
out[4]=0; out[5]=ndcYSign*2*tb; out[6]=0; out[7]=0;
|
|
430
|
+
out[8]=0; out[9]=0; out[10]=(ndcZMin-1)*fn; out[11]=0;
|
|
431
|
+
out[12]=-(right+left)*rl; out[13]=ndcYSign*(-(top+bottom)*tb);
|
|
451
432
|
out[14]=(ndcZMin*far-near)*fn;
|
|
452
433
|
out[15]=1;
|
|
453
434
|
return out;
|
|
@@ -456,19 +437,17 @@ function mat4Ortho(out, left, right, bottom, top, near, far, ndcZMin) {
|
|
|
456
437
|
/**
|
|
457
438
|
* Frustum (off-centre perspective) projection matrix.
|
|
458
439
|
*
|
|
459
|
-
* NDC convention: ndcZMin = WEBGL (−1) or WEBGPU (0).
|
|
460
|
-
*
|
|
461
440
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
462
441
|
* @param {number} left,right,bottom,top Near-plane extents.
|
|
463
442
|
* @param {number} near,far Clip plane distances (positive).
|
|
464
|
-
* @param {number} ndcZMin
|
|
465
|
-
* @
|
|
443
|
+
* @param {number} ndcZMin −1 (WEBGL) or 0 (WEBGPU).
|
|
444
|
+
* @param {number} [ndcYSign=1] +1 = NDC y-up (default); −1 = NDC y-down (native Vulkan).
|
|
466
445
|
*/
|
|
467
|
-
function mat4Frustum(out, left, right, bottom, top, near, far, ndcZMin) {
|
|
446
|
+
function mat4Frustum(out, left, right, bottom, top, near, far, ndcZMin, ndcYSign=1) {
|
|
468
447
|
const rl=1/(right-left), tb=1/(top-bottom);
|
|
469
|
-
out[0]=2*near*rl;
|
|
470
|
-
out[4]=0;
|
|
471
|
-
out[8]=(right+left)*rl;
|
|
448
|
+
out[0]=2*near*rl; out[1]=0; out[2]=0; out[3]=0;
|
|
449
|
+
out[4]=0; out[5]=ndcYSign*2*near*tb; out[6]=0; out[7]=0;
|
|
450
|
+
out[8]=(right+left)*rl; out[9]=ndcYSign*(top+bottom)*tb;
|
|
472
451
|
out[10]=(ndcZMin*near-far)/(far-near);
|
|
473
452
|
out[11]=-1;
|
|
474
453
|
out[12]=0; out[13]=0;
|
|
@@ -482,29 +461,25 @@ function mat4Frustum(out, left, right, bottom, top, near, far, ndcZMin) {
|
|
|
482
461
|
// =========================================================================
|
|
483
462
|
|
|
484
463
|
/**
|
|
485
|
-
* Bias matrix: remaps xyz from NDC to texture/UV space [0,1].
|
|
486
|
-
* xy
|
|
487
|
-
* Used to
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
*
|
|
494
|
-
*
|
|
495
|
-
*
|
|
496
|
-
* [ 0.5 0 0 0
|
|
497
|
-
* [ 0 0
|
|
498
|
-
* [ 0 0 1 0 ]
|
|
499
|
-
* [ 0 0 0 1 ]
|
|
464
|
+
* Bias matrix: remaps xyz from NDC to texture/UV space [0, 1].
|
|
465
|
+
* xy remap from [−1, 1]; z remaps from [ndcZMin, 1].
|
|
466
|
+
* Used to convert light-space NDC coordinates to shadow map UV.
|
|
467
|
+
*
|
|
468
|
+
* Convention note: the standard bias maps NDC y = −1 → texture v = 0 and
|
|
469
|
+
* NDC y = +1 → texture v = 1. This is correct for both NDC y-up and y-down
|
|
470
|
+
* conventions because the shadow map was rendered with the same projection.
|
|
471
|
+
*
|
|
472
|
+
* Column-major (WEBGL, ndcZMin=−1): Column-major (WEBGPU, ndcZMin=0):
|
|
473
|
+
* [ 0.5 0 0 0.5 ] [ 0.5 0 0 0.5 ]
|
|
474
|
+
* [ 0 0.5 0 0.5 ] [ 0 0.5 0 0.5 ]
|
|
475
|
+
* [ 0 0 0.5 0.5 ] [ 0 0 1 0 ]
|
|
476
|
+
* [ 0 0 0 1 ] [ 0 0 0 1 ]
|
|
500
477
|
*
|
|
501
478
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
502
479
|
* @param {number} ndcZMin WEBGL (−1) or WEBGPU (0).
|
|
503
|
-
* @returns {Float32Array|number[]} out
|
|
504
480
|
*/
|
|
505
481
|
function mat4Bias(out, ndcZMin) {
|
|
506
|
-
const sz
|
|
507
|
-
const tz = -ndcZMin / (1 - ndcZMin);
|
|
482
|
+
const sz=1/(1-ndcZMin), tz=-ndcZMin/(1-ndcZMin);
|
|
508
483
|
out[0]=0.5; out[1]=0; out[2]=0; out[3]=0;
|
|
509
484
|
out[4]=0; out[5]=0.5; out[6]=0; out[7]=0;
|
|
510
485
|
out[8]=0; out[9]=0; out[10]=sz; out[11]=0;
|
|
@@ -519,13 +494,12 @@ function mat4Bias(out, ndcZMin) {
|
|
|
519
494
|
* @param {Float32Array|number[]} out 16-element destination.
|
|
520
495
|
* @param {number} nx,ny,nz Unit plane normal.
|
|
521
496
|
* @param {number} d Plane offset (dot(point_on_plane, normal)).
|
|
522
|
-
* @returns {Float32Array|number[]} out
|
|
523
497
|
*/
|
|
524
498
|
function mat4Reflect(out, nx,ny,nz,d) {
|
|
525
|
-
out[0]=1-2*nx*nx;
|
|
526
|
-
out[4]=-2*nx*ny;
|
|
527
|
-
out[8]=-2*nx*nz;
|
|
528
|
-
out[12]=2*d*nx;
|
|
499
|
+
out[0]=1-2*nx*nx; out[1]=-2*ny*nx; out[2]=-2*nz*nx; out[3]=0;
|
|
500
|
+
out[4]=-2*nx*ny; out[5]=1-2*ny*ny; out[6]=-2*nz*ny; out[7]=0;
|
|
501
|
+
out[8]=-2*nx*nz; out[9]=-2*ny*nz; out[10]=1-2*nz*nz; out[11]=0;
|
|
502
|
+
out[12]=2*d*nx; out[13]=2*d*ny; out[14]=2*d*nz; out[15]=1;
|
|
529
503
|
return out;
|
|
530
504
|
}
|
|
531
505
|
|
|
@@ -537,7 +511,6 @@ function mat4Reflect(out, nx,ny,nz,d) {
|
|
|
537
511
|
* Extract translation from a column-major mat4 (column 3).
|
|
538
512
|
* @param {Float32Array|number[]} out3 3-element destination.
|
|
539
513
|
* @param {Float32Array|number[]} m 16-element source.
|
|
540
|
-
* @returns {Float32Array|number[]} out3
|
|
541
514
|
*/
|
|
542
515
|
function mat4ToTranslation(out3, m) {
|
|
543
516
|
out3[0]=m[12]; out3[1]=m[13]; out3[2]=m[14];
|
|
@@ -545,11 +518,10 @@ function mat4ToTranslation(out3, m) {
|
|
|
545
518
|
}
|
|
546
519
|
|
|
547
520
|
/**
|
|
548
|
-
* Extract scale from a column-major mat4 (column lengths of rotation block).
|
|
521
|
+
* Extract scale from a column-major mat4 (column lengths of the rotation block).
|
|
549
522
|
* Assumes no shear.
|
|
550
523
|
* @param {Float32Array|number[]} out3 3-element destination.
|
|
551
524
|
* @param {Float32Array|number[]} m 16-element source.
|
|
552
|
-
* @returns {Float32Array|number[]} out3
|
|
553
525
|
*/
|
|
554
526
|
function mat4ToScale(out3, m) {
|
|
555
527
|
out3[0]=Math.sqrt(m[0]*m[0]+m[1]*m[1]+m[2]*m[2]);
|
|
@@ -560,11 +532,9 @@ function mat4ToScale(out3, m) {
|
|
|
560
532
|
|
|
561
533
|
/**
|
|
562
534
|
* Extract rotation as a unit quaternion from a column-major mat4.
|
|
563
|
-
* Scale is factored out from each column
|
|
564
|
-
* Assumes no shear.
|
|
535
|
+
* Scale is factored out from each column. Assumes no shear.
|
|
565
536
|
* @param {number[]} out4 4-element [x,y,z,w] destination.
|
|
566
537
|
* @param {Float32Array|number[]} m 16-element source.
|
|
567
|
-
* @returns {number[]} out4
|
|
568
538
|
*/
|
|
569
539
|
function mat4ToRotation(out4, m) {
|
|
570
540
|
const sx=Math.sqrt(m[0]*m[0]+m[1]*m[1]+m[2]*m[2])||1;
|
|
@@ -581,28 +551,43 @@ function mat4ToRotation(out4, m) {
|
|
|
581
551
|
* @module tree/query
|
|
582
552
|
* @license AGPL-3.0-only
|
|
583
553
|
*
|
|
584
|
-
* The operative layer — receives
|
|
554
|
+
* The operative layer — receives matrices and extracts information.
|
|
585
555
|
* Contrast with form.js which constructs matrices from specs.
|
|
586
556
|
*
|
|
587
|
-
* form.js —
|
|
588
|
-
* query.js
|
|
589
|
-
*
|
|
590
|
-
* No dependency on form.js. Operating on matrices requires no knowledge
|
|
591
|
-
* of how they were constructed.
|
|
557
|
+
* form.js — specs → matrix
|
|
558
|
+
* query.js — matrix → information
|
|
592
559
|
*
|
|
593
560
|
* Storage: column-major Float32Array / ArrayLike<number>.
|
|
594
|
-
* Element [col*4 + row] = M[row, col].
|
|
595
|
-
*
|
|
596
561
|
* Multiply: mat4Mul(out, A, B) = A · B (standard math order).
|
|
597
|
-
*
|
|
598
562
|
* Pipeline: clip = P · V · M · v
|
|
599
|
-
* P = projection (eye → clip)
|
|
600
|
-
* V = view (world → eye)
|
|
601
|
-
* M = model (local → world)
|
|
602
563
|
*
|
|
603
|
-
* NDC convention
|
|
604
|
-
*
|
|
605
|
-
*
|
|
564
|
+
* ── NDC Z convention ──────────────────────────────────────────────────────
|
|
565
|
+
* Passed as `ndcZMin` to every space-transform function:
|
|
566
|
+
* WEBGL = −1 z ∈ [−1, 1]
|
|
567
|
+
* WEBGPU = 0 z ∈ [ 0, 1]
|
|
568
|
+
*
|
|
569
|
+
* ── NDC Y convention ──────────────────────────────────────────────────────
|
|
570
|
+
* Standard (OpenGL / WebGL / WebGPU browser / Three.js / p5v2):
|
|
571
|
+
* NDC y-up — y = +1 at top, y = −1 at bottom.
|
|
572
|
+
* Native Vulkan: NDC y-down — projections constructed with ndcYSign = −1
|
|
573
|
+
* (see form.js). Query functions are convention-agnostic: they work on
|
|
574
|
+
* whatever matrices are passed in.
|
|
575
|
+
*
|
|
576
|
+
* ── Viewport convention ───────────────────────────────────────────────────
|
|
577
|
+
* vp = [x, y, w, h] — w and h are SIGNED.
|
|
578
|
+
*
|
|
579
|
+
* The sign of h encodes the relationship between NDC y and screen y:
|
|
580
|
+
* h < 0 (e.g. −canvasH): screen y-DOWN (DOM / p5 mouseX·mouseY / Vulkan surface)
|
|
581
|
+
* NDC y=+1 → screen y=0 (top)
|
|
582
|
+
* NDC y=−1 → screen y=H (bottom)
|
|
583
|
+
* h > 0 (e.g. +canvasH): screen y-UP (OpenGL desktop / WebGL gl_FragCoord)
|
|
584
|
+
* NDC y=−1 → screen y=0 (bottom)
|
|
585
|
+
* NDC y=+1 → screen y=H (top)
|
|
586
|
+
*
|
|
587
|
+
* Pass [0, canvasH, canvasW, −canvasH] for p5/DOM coordinates.
|
|
588
|
+
* Pass [0, 0, canvasW, canvasH] for WebGL gl_FragCoord / OpenGL bottom-left.
|
|
589
|
+
* All helpers use vp[2]/vp[3] signed — no Math.abs — so both conventions
|
|
590
|
+
* work automatically without any branching.
|
|
606
591
|
*
|
|
607
592
|
* All functions follow the out-first, zero-allocation contract.
|
|
608
593
|
* Returns null on degeneracy (singular matrix, etc.).
|
|
@@ -610,10 +595,10 @@ function mat4ToRotation(out4, m) {
|
|
|
610
595
|
|
|
611
596
|
|
|
612
597
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
613
|
-
// Mat4
|
|
598
|
+
// Mat4 arithmetic
|
|
614
599
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
615
600
|
|
|
616
|
-
/** out = A · B (column-major
|
|
601
|
+
/** out = A · B (column-major) */
|
|
617
602
|
function mat4Mul(out, A, B) {
|
|
618
603
|
const a0=A[0],a1=A[1],a2=A[2],a3=A[3],
|
|
619
604
|
a4=A[4],a5=A[5],a6=A[6],a7=A[7],
|
|
@@ -642,229 +627,164 @@ function mat4Mul(out, A, B) {
|
|
|
642
627
|
return out;
|
|
643
628
|
}
|
|
644
629
|
|
|
645
|
-
/** out = inverse(src).
|
|
630
|
+
/** out = inverse(src). Returns null if singular (|det| < 1e-12). */
|
|
646
631
|
function mat4Invert(out, src) {
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
b08=a20*a33-a23*a30,b09=a21*a32-a22*a31,
|
|
657
|
-
b10=a21*a33-a23*a31,b11=a22*a33-a23*a32;
|
|
658
|
-
let det=b00*b11-b01*b10+b02*b09+b03*b08-b04*b07+b05*b06;
|
|
632
|
+
const s0=src[0],s1=src[1],s2=src[2],s3=src[3],
|
|
633
|
+
s4=src[4],s5=src[5],s6=src[6],s7=src[7],
|
|
634
|
+
s8=src[8],s9=src[9],s10=src[10],s11=src[11],
|
|
635
|
+
s12=src[12],s13=src[13],s14=src[14],s15=src[15];
|
|
636
|
+
const b0=s0*s5-s1*s4, b1=s0*s6-s2*s4, b2=s0*s7-s3*s4,
|
|
637
|
+
b3=s1*s6-s2*s5, b4=s1*s7-s3*s5, b5=s2*s7-s3*s6,
|
|
638
|
+
b6=s8*s13-s9*s12, b7=s8*s14-s10*s12, b8=s8*s15-s11*s12,
|
|
639
|
+
b9=s9*s14-s10*s13, b10=s9*s15-s11*s13, b11=s10*s15-s11*s14;
|
|
640
|
+
let det=b0*b11-b1*b10+b2*b9+b3*b8-b4*b7+b5*b6;
|
|
659
641
|
if (Math.abs(det) < 1e-12) return null;
|
|
660
|
-
det=1/det;
|
|
661
|
-
out[0]=(
|
|
662
|
-
out[1]=(
|
|
663
|
-
out[2]=(
|
|
664
|
-
out[3]=(
|
|
665
|
-
out[4]=(
|
|
666
|
-
out[5]=(
|
|
667
|
-
out[6]=(
|
|
668
|
-
out[7]=(
|
|
669
|
-
out[8]=(
|
|
670
|
-
out[9]=(
|
|
671
|
-
out[10]=(
|
|
672
|
-
out[11]=(
|
|
673
|
-
out[12]=(
|
|
674
|
-
out[13]=(
|
|
675
|
-
out[14]=(
|
|
676
|
-
out[15]=(
|
|
642
|
+
det = 1/det;
|
|
643
|
+
out[0]=(s5*b11-s6*b10+s7*b9)*det;
|
|
644
|
+
out[1]=(s2*b10-s1*b11-s3*b9)*det;
|
|
645
|
+
out[2]=(s13*b5-s14*b4+s15*b3)*det;
|
|
646
|
+
out[3]=(s10*b4-s9*b5-s11*b3)*det;
|
|
647
|
+
out[4]=(s6*b8-s4*b11-s7*b7)*det;
|
|
648
|
+
out[5]=(s0*b11-s2*b8+s3*b7)*det;
|
|
649
|
+
out[6]=(s14*b2-s12*b5-s15*b1)*det;
|
|
650
|
+
out[7]=(s8*b5-s10*b2+s11*b1)*det;
|
|
651
|
+
out[8]=(s4*b10-s5*b8+s7*b6)*det;
|
|
652
|
+
out[9]=(s1*b8-s0*b10-s3*b6)*det;
|
|
653
|
+
out[10]=(s12*b4-s13*b2+s15*b0)*det;
|
|
654
|
+
out[11]=(s9*b2-s8*b4-s11*b0)*det;
|
|
655
|
+
out[12]=(s5*b7-s4*b9-s6*b6)*det;
|
|
656
|
+
out[13]=(s0*b9-s1*b7+s2*b6)*det;
|
|
657
|
+
out[14]=(s13*b1-s12*b3-s14*b0)*det;
|
|
658
|
+
out[15]=(s8*b3-s9*b1+s10*b0)*det;
|
|
677
659
|
return out;
|
|
678
660
|
}
|
|
679
661
|
|
|
680
|
-
/**
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
t=src[3];out[3]=src[12];out[12]=t;
|
|
687
|
-
t=src[6];out[6]=src[9];out[9]=t;
|
|
688
|
-
t=src[7];out[7]=src[13];out[13]=t;
|
|
689
|
-
t=src[11];out[11]=src[14];out[14]=t;
|
|
690
|
-
} else {
|
|
691
|
-
out[0]=src[0];out[1]=src[4];out[2]=src[8];out[3]=src[12];
|
|
692
|
-
out[4]=src[1];out[5]=src[5];out[6]=src[9];out[7]=src[13];
|
|
693
|
-
out[8]=src[2];out[9]=src[6];out[10]=src[10];out[11]=src[14];
|
|
694
|
-
out[12]=src[3];out[13]=src[7];out[14]=src[11];out[15]=src[15];
|
|
695
|
-
}
|
|
696
|
-
return out;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
/** out[0..8] = inverseTranspose(upper3×3(src)) (normal matrix) */
|
|
662
|
+
/**
|
|
663
|
+
* Normal matrix: inverseTranspose(upper-left 3×3 of src).
|
|
664
|
+
* On degeneracy writes zeros and returns out.
|
|
665
|
+
* @param {Float32Array|number[]} out 9-element destination.
|
|
666
|
+
* @param {Float32Array|number[]} src 16-element mat4.
|
|
667
|
+
*/
|
|
700
668
|
function mat3NormalFromMat4(out, src) {
|
|
701
669
|
const a00=src[0],a01=src[1],a02=src[2],
|
|
702
670
|
a10=src[4],a11=src[5],a12=src[6],
|
|
703
671
|
a20=src[8],a21=src[9],a22=src[10];
|
|
704
|
-
const b01=a22*a11-a12*a21,
|
|
705
|
-
b11=-a22*a01+a02*a21,
|
|
706
|
-
b21=a12*a01-a02*a11;
|
|
672
|
+
const b01=a22*a11-a12*a21, b11=-a22*a01+a02*a21, b21=a12*a01-a02*a11;
|
|
707
673
|
let det=a00*b01+a10*b11+a20*b21;
|
|
708
674
|
if (Math.abs(det) < 1e-12) { for(let i=0;i<9;i++)out[i]=0; return out; }
|
|
709
675
|
det=1/det;
|
|
710
|
-
out[0]=b01*det;
|
|
711
|
-
out[
|
|
712
|
-
out[
|
|
713
|
-
out[3]=b11*det;
|
|
714
|
-
out[4]=(a22*a00-a02*a20)*det;
|
|
715
|
-
out[5]=(-a21*a00+a01*a20)*det;
|
|
716
|
-
out[6]=b21*det;
|
|
717
|
-
out[7]=(-a12*a00+a02*a10)*det;
|
|
718
|
-
out[8]=(a11*a00-a01*a10)*det;
|
|
676
|
+
out[0]=b01*det; out[1]=(-a22*a10+a12*a20)*det; out[2]=(a21*a10-a11*a20)*det;
|
|
677
|
+
out[3]=b11*det; out[4]=(a22*a00-a02*a20)*det; out[5]=(-a21*a00+a01*a20)*det;
|
|
678
|
+
out[6]=b21*det; out[7]=(-a12*a00+a02*a10)*det; out[8]=(a11*a00-a01*a10)*det;
|
|
719
679
|
return out;
|
|
720
680
|
}
|
|
721
681
|
|
|
722
|
-
/** out = mat4 * [x,y,z,1], perspective-divides, writes xyz */
|
|
682
|
+
/** out = mat4 * [x,y,z,1], perspective-divides, writes xyz. */
|
|
723
683
|
function mat4MulPoint(out, m, x, y, z) {
|
|
724
|
-
const rx
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
if (rw !== 0 && rw !== 1) {
|
|
729
|
-
out[0] = rx/rw; out[1] = ry/rw; out[2] = rz/rw;
|
|
730
|
-
} else {
|
|
731
|
-
out[0] = rx; out[1] = ry; out[2] = rz;
|
|
732
|
-
}
|
|
684
|
+
const rx=m[0]*x+m[4]*y+m[8]*z+m[12], ry=m[1]*x+m[5]*y+m[9]*z+m[13],
|
|
685
|
+
rz=m[2]*x+m[6]*y+m[10]*z+m[14], rw=m[3]*x+m[7]*y+m[11]*z+m[15];
|
|
686
|
+
if (rw!==0&&rw!==1) { out[0]=rx/rw; out[1]=ry/rw; out[2]=rz/rw; }
|
|
687
|
+
else { out[0]=rx; out[1]=ry; out[2]=rz; }
|
|
733
688
|
return out;
|
|
734
689
|
}
|
|
735
690
|
|
|
736
691
|
/**
|
|
737
|
-
* Apply only the 3×3 linear block of a mat4 to a direction
|
|
738
|
-
*
|
|
739
|
-
* when the matrix is known to be orthogonal (use mat3NormalFromMat4 for normals
|
|
740
|
-
* under non-uniform scale).
|
|
741
|
-
*
|
|
742
|
-
* @param {Float32Array|number[]} out 3-element destination.
|
|
743
|
-
* @param {Float32Array|number[]} m 16-element mat4.
|
|
744
|
-
* @param {number} dx,dy,dz Input direction.
|
|
745
|
-
* @returns {Float32Array|number[]} out
|
|
692
|
+
* Apply only the 3×3 linear block of a mat4 to a direction (no translation,
|
|
693
|
+
* no perspective divide). Use mat3NormalFromMat4 for normals under non-uniform scale.
|
|
746
694
|
*/
|
|
747
695
|
function mat4MulDir(out, m, dx, dy, dz) {
|
|
748
|
-
out[0]
|
|
749
|
-
out[1]
|
|
750
|
-
out[2]
|
|
696
|
+
out[0]=m[0]*dx+m[4]*dy+m[8]*dz;
|
|
697
|
+
out[1]=m[1]*dx+m[5]*dy+m[9]*dz;
|
|
698
|
+
out[2]=m[2]*dx+m[6]*dy+m[10]*dz;
|
|
751
699
|
return out;
|
|
752
700
|
}
|
|
753
701
|
|
|
754
702
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
755
|
-
// Projection queries
|
|
703
|
+
// Projection queries
|
|
756
704
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
757
705
|
|
|
758
|
-
/** @returns {boolean} true if orthographic */
|
|
706
|
+
/** @returns {boolean} true if orthographic. */
|
|
759
707
|
function projIsOrtho(p) { return p[15] !== 0; }
|
|
760
708
|
|
|
761
709
|
/**
|
|
762
710
|
* Near plane distance.
|
|
763
|
-
* @param {ArrayLike<number>} p
|
|
764
|
-
* @param {number}
|
|
711
|
+
* @param {ArrayLike<number>} p Projection mat4.
|
|
712
|
+
* @param {number} ndcZMin WEBGL (−1) or WEBGPU (0).
|
|
765
713
|
*/
|
|
766
714
|
function projNear(p, ndcZMin) {
|
|
767
|
-
return p[15]
|
|
768
|
-
? p[14] / (p[10] + ndcZMin)
|
|
769
|
-
: (p[14] - ndcZMin) / p[10];
|
|
715
|
+
return p[15]===0 ? p[14]/(p[10]+ndcZMin) : (p[14]-ndcZMin)/p[10];
|
|
770
716
|
}
|
|
771
717
|
|
|
772
|
-
/** Far plane distance (
|
|
718
|
+
/** Far plane distance (far always maps to NDC z = 1, convention-independent). */
|
|
773
719
|
function projFar(p) {
|
|
774
|
-
return p[15]
|
|
775
|
-
? p[14] / (1 + p[10])
|
|
776
|
-
: (p[14] - 1) / p[10];
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
function projLeft(p, ndcZMin) {
|
|
780
|
-
return p[15] === 1
|
|
781
|
-
? -(1 + p[12]) / p[0]
|
|
782
|
-
: projNear(p, ndcZMin) * (p[8] - 1) / p[0];
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
function projRight(p, ndcZMin) {
|
|
786
|
-
return p[15] === 1
|
|
787
|
-
? (1 - p[12]) / p[0]
|
|
788
|
-
: projNear(p, ndcZMin) * (1 + p[8]) / p[0];
|
|
720
|
+
return p[15]===0 ? p[14]/(1+p[10]) : (p[14]-1)/p[10];
|
|
789
721
|
}
|
|
790
722
|
|
|
791
|
-
function
|
|
792
|
-
|
|
793
|
-
? (p[13] - 1) / p[5]
|
|
794
|
-
: projNear(p, ndcZMin) * (p[9] - 1) / p[5];
|
|
795
|
-
}
|
|
723
|
+
function projLeft (p, ndcZMin) { return p[15]===1 ? -(1+p[12])/p[0] : projNear(p,ndcZMin)*(p[8]-1)/p[0]; }
|
|
724
|
+
function projRight (p, ndcZMin) { return p[15]===1 ? (1-p[12])/p[0] : projNear(p,ndcZMin)*(1+p[8])/p[0]; }
|
|
796
725
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
}
|
|
726
|
+
/**
|
|
727
|
+
* Top extent of the near plane in camera space (y_max).
|
|
728
|
+
* Positive for a standard y-up camera.
|
|
729
|
+
* @param {ArrayLike<number>} p Projection mat4.
|
|
730
|
+
* @param {number} ndcZMin WEBGL (−1) or WEBGPU (0).
|
|
731
|
+
*/
|
|
732
|
+
function projTop (p, ndcZMin) { return p[15]===1 ? (1+p[13])/p[5] : projNear(p,ndcZMin)*(1+p[9])/p[5]; }
|
|
802
733
|
|
|
803
|
-
/**
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
}
|
|
734
|
+
/**
|
|
735
|
+
* Bottom extent of the near plane in camera space (y_min).
|
|
736
|
+
* Negative for a standard y-up camera.
|
|
737
|
+
* @param {ArrayLike<number>} p Projection mat4.
|
|
738
|
+
* @param {number} ndcZMin WEBGL (−1) or WEBGPU (0).
|
|
739
|
+
*/
|
|
740
|
+
function projBottom(p, ndcZMin) { return p[15]===1 ? (p[13]-1)/p[5] : projNear(p,ndcZMin)*(p[9]-1)/p[5]; }
|
|
807
741
|
|
|
808
|
-
/**
|
|
809
|
-
function
|
|
810
|
-
|
|
811
|
-
}
|
|
742
|
+
/** Vertical field of view in radians (perspective only). */
|
|
743
|
+
function projFov (p) { return Math.abs(2*Math.atan(1/p[5])); }
|
|
744
|
+
/** Horizontal field of view in radians (perspective only). */
|
|
745
|
+
function projHfov(p) { return Math.abs(2*Math.atan(1/p[0])); }
|
|
812
746
|
|
|
813
747
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
814
|
-
// Derived matrices
|
|
748
|
+
// Derived matrices
|
|
815
749
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
816
750
|
|
|
817
751
|
/** out = P · V */
|
|
818
|
-
function mat4PV(out, proj, view)
|
|
819
|
-
|
|
752
|
+
function mat4PV(out, proj, view) { return mat4Mul(out, proj, view); }
|
|
820
753
|
/** out = V · M */
|
|
821
754
|
function mat4MV(out, model, view) { return mat4Mul(out, view, model); }
|
|
822
755
|
|
|
823
756
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
824
|
-
//
|
|
757
|
+
// Frame-relative transforms
|
|
825
758
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
826
759
|
|
|
827
760
|
/**
|
|
828
|
-
*
|
|
829
|
-
* @
|
|
830
|
-
* @param {ArrayLike<number>} from Source frame transform.
|
|
831
|
-
* @param {ArrayLike<number>} to Destination frame transform.
|
|
832
|
-
* @returns {ArrayLike<number>|null} out, or null if to is singular.
|
|
761
|
+
* Location transform between frames: out = inv(to) · from.
|
|
762
|
+
* @returns {ArrayLike<number>|null} out, or null if `to` is singular.
|
|
833
763
|
*/
|
|
834
764
|
function mat4Location(out, from, to) {
|
|
835
765
|
return mat4Invert(out, to) && mat4Mul(out, out, from);
|
|
836
766
|
}
|
|
837
767
|
|
|
838
768
|
/**
|
|
839
|
-
*
|
|
840
|
-
* Uses only the upper-left 3×3 blocks,
|
|
841
|
-
* @
|
|
842
|
-
* @param {ArrayLike<number>} from Source frame transform.
|
|
843
|
-
* @param {ArrayLike<number>} to Destination frame transform.
|
|
844
|
-
* @returns {ArrayLike<number>|null} out, or null if from is singular.
|
|
769
|
+
* Direction transform between frames: out = to₃ · inv(from₃).
|
|
770
|
+
* Uses only the upper-left 3×3 blocks (rotation/scale, no translation).
|
|
771
|
+
* @returns {ArrayLike<number>|null} out, or null if `from` is singular.
|
|
845
772
|
*/
|
|
846
773
|
function mat3Direction(out, from, to) {
|
|
847
|
-
const a00=from[0],
|
|
848
|
-
a10=from[4],
|
|
849
|
-
a20=from[8],
|
|
850
|
-
const b01=a22*a11-a12*a21,
|
|
851
|
-
b11=a12*a20-a22*a10,
|
|
852
|
-
b21=a21*a10-a11*a20;
|
|
774
|
+
const a00=from[0],a01=from[1],a02=from[2],
|
|
775
|
+
a10=from[4],a11=from[5],a12=from[6],
|
|
776
|
+
a20=from[8],a21=from[9],a22=from[10];
|
|
777
|
+
const b01=a22*a11-a12*a21, b11=a12*a20-a22*a10, b21=a21*a10-a11*a20;
|
|
853
778
|
let det=a00*b01+a01*b11+a02*b21;
|
|
854
779
|
if (Math.abs(det) < 1e-12) return null;
|
|
855
780
|
det=1/det;
|
|
856
|
-
const i00=b01*det,
|
|
857
|
-
const i10=b11*det,
|
|
858
|
-
const i20=b21*det,
|
|
859
|
-
const t00=to[0],
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
const m10=t00*i10+t10*i11+t20*i12, m11=t01*i10+t11*i11+t21*i12, m12=t02*i10+t12*i11+t22*i12;
|
|
864
|
-
const m20=t00*i20+t10*i21+t20*i22, m21=t01*i20+t11*i21+t21*i22, m22=t02*i20+t12*i21+t22*i22;
|
|
865
|
-
out[0]=m00; out[1]=m10; out[2]=m20;
|
|
866
|
-
out[3]=m01; out[4]=m11; out[5]=m21;
|
|
867
|
-
out[6]=m02; out[7]=m12; out[8]=m22;
|
|
781
|
+
const i00=b01*det, i01=(a02*a21-a22*a01)*det, i02=(a12*a01-a02*a11)*det;
|
|
782
|
+
const i10=b11*det, i11=(a22*a00-a02*a20)*det, i12=(a02*a10-a12*a00)*det;
|
|
783
|
+
const i20=b21*det, i21=(a01*a20-a21*a00)*det, i22=(a11*a00-a01*a10)*det;
|
|
784
|
+
const t00=to[0],t01=to[1],t02=to[2], t10=to[4],t11=to[5],t12=to[6], t20=to[8],t21=to[9],t22=to[10];
|
|
785
|
+
out[0]=t00*i00+t10*i01+t20*i02; out[1]=t01*i00+t11*i01+t21*i02; out[2]=t02*i00+t12*i01+t22*i02;
|
|
786
|
+
out[3]=t00*i10+t10*i11+t20*i12; out[4]=t01*i10+t11*i11+t21*i12; out[5]=t02*i10+t12*i11+t22*i12;
|
|
787
|
+
out[6]=t00*i20+t10*i21+t20*i22; out[7]=t01*i20+t11*i21+t21*i22; out[8]=t02*i20+t12*i21+t22*i22;
|
|
868
788
|
return out;
|
|
869
789
|
}
|
|
870
790
|
|
|
@@ -872,215 +792,177 @@ function mat3Direction(out, from, to) {
|
|
|
872
792
|
// Space transforms — mapLocation / mapDirection
|
|
873
793
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
874
794
|
//
|
|
875
|
-
//
|
|
876
|
-
//
|
|
877
|
-
//
|
|
795
|
+
// Flat dispatch: every from→to pair is a self-contained leaf with only stack
|
|
796
|
+
// locals — no reentrancy, no shared state between calls.
|
|
797
|
+
//
|
|
798
|
+
// Matrices bag `m`:
|
|
799
|
+
// mat4Proj Float32Array(16) projection (eye → clip)
|
|
800
|
+
// mat4View Float32Array(16) view (world → eye)
|
|
801
|
+
// mat4Eye? Float32Array(16) eye (eye → world); caller fills before passing
|
|
802
|
+
// mat4PV? Float32Array(16) P · V; caller fills or _ensurePV allocates once
|
|
803
|
+
// mat4PVInv? Float32Array(16) inv(P · V); caller fills
|
|
804
|
+
// fromFrame? Float32Array(16) MATRIX source frame
|
|
805
|
+
// toFrameInv? Float32Array(16) inv(MATRIX dest frame)
|
|
878
806
|
//
|
|
879
|
-
//
|
|
880
|
-
//
|
|
881
|
-
//
|
|
882
|
-
//
|
|
883
|
-
//
|
|
884
|
-
// pvMatrix?: Float32Array(16) — P · V; lazy
|
|
885
|
-
// ipvMatrix?: Float32Array(16) — inv(P · V); lazy
|
|
886
|
-
// fromFrame?: Float32Array(16) — MATRIX source frame (custom space)
|
|
887
|
-
// toFrameInv?:Float32Array(16) — inv(MATRIX dest frame)
|
|
888
|
-
// }
|
|
807
|
+
// Viewport `vp` = [x, y, w, h]:
|
|
808
|
+
// Use SIGNED h to encode screen-y direction (see module header).
|
|
809
|
+
// Core formula: screen = (ndc*0.5+0.5)*vp[k] + vp[k-2] (k=2 for x, k=3 for y)
|
|
810
|
+
// Inverse: ndc = ((screen-vp[k-2])/vp[k])*2 - 1
|
|
811
|
+
// Negative vp[3] flips NDC y-up to screen y-down automatically.
|
|
889
812
|
//
|
|
890
813
|
|
|
891
|
-
// ── Location
|
|
814
|
+
// ── Location helpers ─────────────────────────────────────────────────────
|
|
892
815
|
|
|
893
816
|
function _worldToScreen(out, px, py, pz, pv, vp, ndcZMin) {
|
|
894
|
-
const x
|
|
895
|
-
|
|
896
|
-
const
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
const vpX=vp[0], vpY=vp[1], vpW=Math.abs(vp[2]), vpH=Math.abs(vp[3]);
|
|
901
|
-
out[0] = vpX + vpW * (nx + 1) * 0.5;
|
|
902
|
-
out[1] = vpY + vpH * (1 - (ny + 1) * 0.5);
|
|
903
|
-
out[2] = (nz - ndcZMin) / (1 - ndcZMin);
|
|
817
|
+
const x=pv[0]*px+pv[4]*py+pv[8]*pz+pv[12], y=pv[1]*px+pv[5]*py+pv[9]*pz+pv[13],
|
|
818
|
+
z=pv[2]*px+pv[6]*py+pv[10]*pz+pv[14], w=pv[3]*px+pv[7]*py+pv[11]*pz+pv[15];
|
|
819
|
+
const xi=(w!==0&&w!==1)?1/w:1;
|
|
820
|
+
out[0]=(x*xi*0.5+0.5)*vp[2]+vp[0];
|
|
821
|
+
out[1]=(y*xi*0.5+0.5)*vp[3]+vp[1];
|
|
822
|
+
out[2]=(z*xi-ndcZMin)/(1-ndcZMin);
|
|
904
823
|
return out;
|
|
905
824
|
}
|
|
906
825
|
|
|
907
826
|
function _screenToWorld(out, sx, sy, sz, ipv, vp, ndcZMin) {
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
return mat4MulPoint(out, ipv, nx, ny, nz);
|
|
827
|
+
return mat4MulPoint(out, ipv,
|
|
828
|
+
((sx-vp[0])/vp[2])*2-1,
|
|
829
|
+
((sy-vp[1])/vp[3])*2-1,
|
|
830
|
+
sz*(1-ndcZMin)+ndcZMin);
|
|
913
831
|
}
|
|
914
832
|
|
|
915
833
|
function _worldToNDC(out, px, py, pz, pv) {
|
|
916
|
-
const x=pv[0]*px+pv[4]*py+pv[8]*pz+pv[12]
|
|
917
|
-
|
|
918
|
-
const
|
|
919
|
-
const w=pv[3]*px+pv[7]*py+pv[11]*pz+pv[15];
|
|
920
|
-
const xi = (w !== 0 && w !== 1) ? 1/w : 1;
|
|
834
|
+
const x=pv[0]*px+pv[4]*py+pv[8]*pz+pv[12], y=pv[1]*px+pv[5]*py+pv[9]*pz+pv[13],
|
|
835
|
+
z=pv[2]*px+pv[6]*py+pv[10]*pz+pv[14], w=pv[3]*px+pv[7]*py+pv[11]*pz+pv[15];
|
|
836
|
+
const xi=(w!==0&&w!==1)?1/w:1;
|
|
921
837
|
out[0]=x*xi; out[1]=y*xi; out[2]=z*xi;
|
|
922
838
|
return out;
|
|
923
839
|
}
|
|
924
840
|
|
|
925
|
-
function _ndcToWorld(out, nx, ny, nz, ipv) {
|
|
926
|
-
return mat4MulPoint(out, ipv, nx, ny, nz);
|
|
927
|
-
}
|
|
841
|
+
function _ndcToWorld(out, nx, ny, nz, ipv) { return mat4MulPoint(out,ipv,nx,ny,nz); }
|
|
928
842
|
|
|
929
843
|
function _screenToNDC(out, sx, sy, sz, vp, ndcZMin) {
|
|
930
|
-
|
|
931
|
-
out[
|
|
932
|
-
out[
|
|
933
|
-
out[2] = sz * (1 - ndcZMin) + ndcZMin;
|
|
844
|
+
out[0]=((sx-vp[0])/vp[2])*2-1;
|
|
845
|
+
out[1]=((sy-vp[1])/vp[3])*2-1;
|
|
846
|
+
out[2]=sz*(1-ndcZMin)+ndcZMin;
|
|
934
847
|
return out;
|
|
935
848
|
}
|
|
936
849
|
|
|
937
850
|
function _ndcToScreen(out, nx, ny, nz, vp, ndcZMin) {
|
|
938
|
-
|
|
939
|
-
out[
|
|
940
|
-
out[
|
|
941
|
-
out[2] = (nz - ndcZMin) / (1 - ndcZMin);
|
|
851
|
+
out[0]=(nx*0.5+0.5)*vp[2]+vp[0];
|
|
852
|
+
out[1]=(ny*0.5+0.5)*vp[3]+vp[1];
|
|
853
|
+
out[2]=(nz-ndcZMin)/(1-ndcZMin);
|
|
942
854
|
return out;
|
|
943
855
|
}
|
|
944
856
|
|
|
945
857
|
function _ensurePV(m) {
|
|
946
|
-
if (m.
|
|
947
|
-
m.
|
|
948
|
-
mat4Mul(m.
|
|
949
|
-
return m.
|
|
858
|
+
if (m.mat4PV) return m.mat4PV;
|
|
859
|
+
m.mat4PV = new Float32Array(16);
|
|
860
|
+
mat4Mul(m.mat4PV, m.mat4Proj, m.mat4View);
|
|
861
|
+
return m.mat4PV;
|
|
950
862
|
}
|
|
951
863
|
|
|
952
864
|
/**
|
|
953
865
|
* Map a point between named coordinate spaces.
|
|
954
866
|
*
|
|
955
|
-
* @param {
|
|
956
|
-
* @param {number}
|
|
957
|
-
* @param {string}
|
|
958
|
-
* @param {string}
|
|
959
|
-
* @param {object}
|
|
960
|
-
*
|
|
961
|
-
* @param {
|
|
962
|
-
* @
|
|
867
|
+
* @param {number[]} out 3-element destination — written and returned.
|
|
868
|
+
* @param {number} px,py,pz Input point.
|
|
869
|
+
* @param {string} from Source space (WORLD, EYE, SCREEN, NDC, MATRIX).
|
|
870
|
+
* @param {string} to Destination space.
|
|
871
|
+
* @param {object} m Matrices bag — see module header.
|
|
872
|
+
* @param {number[]} vp Viewport [x, y, w, h]; sign of h encodes screen-y direction.
|
|
873
|
+
* @param {number} ndcZMin WEBGL (−1) or WEBGPU (0).
|
|
874
|
+
* @returns {number[]} out
|
|
963
875
|
*/
|
|
964
876
|
function mapLocation(out, px, py, pz, from, to, m, vp, ndcZMin) {
|
|
965
|
-
|
|
966
|
-
if (from
|
|
967
|
-
|
|
968
|
-
if (from
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
if (from
|
|
973
|
-
|
|
974
|
-
if (from
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
return
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
// WORLD ↔ EYE
|
|
984
|
-
if (from === WORLD && to === EYE)
|
|
985
|
-
return mat4MulPoint(out, m.vMatrix, px,py,pz);
|
|
986
|
-
if (from === EYE && to === WORLD)
|
|
987
|
-
return mat4MulPoint(out, m.eMatrix, px,py,pz);
|
|
988
|
-
|
|
989
|
-
// EYE ↔ SCREEN
|
|
990
|
-
if (from === EYE && to === SCREEN) {
|
|
991
|
-
const e = m.eMatrix;
|
|
992
|
-
const ex=e[0]*px+e[4]*py+e[8]*pz+e[12],
|
|
993
|
-
ey=e[1]*px+e[5]*py+e[9]*pz+e[13],
|
|
994
|
-
ez=e[2]*px+e[6]*py+e[10]*pz+e[14];
|
|
995
|
-
return _worldToScreen(out, ex,ey,ez, _ensurePV(m), vp, ndcZMin);
|
|
877
|
+
if (from===WORLD && to===SCREEN) return _worldToScreen(out,px,py,pz,_ensurePV(m),vp,ndcZMin);
|
|
878
|
+
if (from===SCREEN && to===WORLD) return _screenToWorld(out,px,py,pz,m.mat4PVInv,vp,ndcZMin);
|
|
879
|
+
|
|
880
|
+
if (from===WORLD && to===NDC) return _worldToNDC(out,px,py,pz,_ensurePV(m));
|
|
881
|
+
if (from===NDC && to===WORLD) return _ndcToWorld(out,px,py,pz,m.mat4PVInv);
|
|
882
|
+
|
|
883
|
+
if (from===SCREEN && to===NDC) return _screenToNDC(out,px,py,pz,vp,ndcZMin);
|
|
884
|
+
if (from===NDC && to===SCREEN) return _ndcToScreen(out,px,py,pz,vp,ndcZMin);
|
|
885
|
+
|
|
886
|
+
if (from===WORLD && to===EYE) return mat4MulPoint(out,m.mat4View,px,py,pz);
|
|
887
|
+
if (from===EYE && to===WORLD) return mat4MulPoint(out,m.mat4Eye,px,py,pz);
|
|
888
|
+
|
|
889
|
+
if (from===EYE && to===SCREEN) {
|
|
890
|
+
const e=m.mat4Eye;
|
|
891
|
+
return _worldToScreen(out,e[0]*px+e[4]*py+e[8]*pz+e[12],
|
|
892
|
+
e[1]*px+e[5]*py+e[9]*pz+e[13],
|
|
893
|
+
e[2]*px+e[6]*py+e[10]*pz+e[14],_ensurePV(m),vp,ndcZMin);
|
|
996
894
|
}
|
|
997
|
-
if (from
|
|
998
|
-
_screenToWorld(out,
|
|
999
|
-
|
|
1000
|
-
return mat4MulPoint(out, m.vMatrix, wx,wy,wz);
|
|
895
|
+
if (from===SCREEN && to===EYE) {
|
|
896
|
+
_screenToWorld(out,px,py,pz,m.mat4PVInv,vp,ndcZMin);
|
|
897
|
+
return mat4MulPoint(out,m.mat4View,out[0],out[1],out[2]);
|
|
1001
898
|
}
|
|
1002
899
|
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
ez=e[2]*px+e[6]*py+e[10]*pz+e[14];
|
|
1009
|
-
return _worldToNDC(out, ex,ey,ez, _ensurePV(m));
|
|
900
|
+
if (from===EYE && to===NDC) {
|
|
901
|
+
const e=m.mat4Eye;
|
|
902
|
+
return _worldToNDC(out,e[0]*px+e[4]*py+e[8]*pz+e[12],
|
|
903
|
+
e[1]*px+e[5]*py+e[9]*pz+e[13],
|
|
904
|
+
e[2]*px+e[6]*py+e[10]*pz+e[14],_ensurePV(m));
|
|
1010
905
|
}
|
|
1011
|
-
if (from
|
|
1012
|
-
_ndcToWorld(out,
|
|
1013
|
-
|
|
1014
|
-
return mat4MulPoint(out, m.vMatrix, wx,wy,wz);
|
|
906
|
+
if (from===NDC && to===EYE) {
|
|
907
|
+
_ndcToWorld(out,px,py,pz,m.mat4PVInv);
|
|
908
|
+
return mat4MulPoint(out,m.mat4View,out[0],out[1],out[2]);
|
|
1015
909
|
}
|
|
1016
910
|
|
|
1017
|
-
|
|
1018
|
-
if (from
|
|
1019
|
-
|
|
1020
|
-
if (from
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
const f = m.fromFrame;
|
|
1026
|
-
const fx=f[0]*px+f[4]*py+f[8]*pz+f[12],
|
|
1027
|
-
fy=f[1]*px+f[5]*py+f[9]*pz+f[13],
|
|
1028
|
-
fz=f[2]*px+f[6]*py+f[10]*pz+f[14];
|
|
1029
|
-
return mat4MulPoint(out, m.vMatrix, fx,fy,fz);
|
|
911
|
+
if (from===MATRIX && to===WORLD) return mat4MulPoint(out,m.fromFrame,px,py,pz);
|
|
912
|
+
if (from===WORLD && to===MATRIX) return mat4MulPoint(out,m.toFrameInv,px,py,pz);
|
|
913
|
+
|
|
914
|
+
if (from===MATRIX && to===EYE) {
|
|
915
|
+
const f=m.fromFrame;
|
|
916
|
+
return mat4MulPoint(out,m.mat4View,f[0]*px+f[4]*py+f[8]*pz+f[12],
|
|
917
|
+
f[1]*px+f[5]*py+f[9]*pz+f[13],
|
|
918
|
+
f[2]*px+f[6]*py+f[10]*pz+f[14]);
|
|
1030
919
|
}
|
|
1031
|
-
if (from
|
|
1032
|
-
const e
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
return mat4MulPoint(out, m.toFrameInv, ex,ey,ez);
|
|
920
|
+
if (from===EYE && to===MATRIX) {
|
|
921
|
+
const e=m.mat4Eye;
|
|
922
|
+
return mat4MulPoint(out,m.toFrameInv,e[0]*px+e[4]*py+e[8]*pz+e[12],
|
|
923
|
+
e[1]*px+e[5]*py+e[9]*pz+e[13],
|
|
924
|
+
e[2]*px+e[6]*py+e[10]*pz+e[14]);
|
|
1037
925
|
}
|
|
1038
926
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
fz=f[2]*px+f[6]*py+f[10]*pz+f[14];
|
|
1045
|
-
return _worldToScreen(out, fx,fy,fz, _ensurePV(m), vp, ndcZMin);
|
|
927
|
+
if (from===MATRIX && to===SCREEN) {
|
|
928
|
+
const f=m.fromFrame;
|
|
929
|
+
return _worldToScreen(out,f[0]*px+f[4]*py+f[8]*pz+f[12],
|
|
930
|
+
f[1]*px+f[5]*py+f[9]*pz+f[13],
|
|
931
|
+
f[2]*px+f[6]*py+f[10]*pz+f[14],_ensurePV(m),vp,ndcZMin);
|
|
1046
932
|
}
|
|
1047
|
-
if (from
|
|
1048
|
-
_screenToWorld(out,
|
|
1049
|
-
|
|
1050
|
-
return mat4MulPoint(out, m.toFrameInv, wx,wy,wz);
|
|
933
|
+
if (from===SCREEN && to===MATRIX) {
|
|
934
|
+
_screenToWorld(out,px,py,pz,m.mat4PVInv,vp,ndcZMin);
|
|
935
|
+
return mat4MulPoint(out,m.toFrameInv,out[0],out[1],out[2]);
|
|
1051
936
|
}
|
|
1052
937
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
fz=f[2]*px+f[6]*py+f[10]*pz+f[14];
|
|
1059
|
-
return _worldToNDC(out, fx,fy,fz, _ensurePV(m));
|
|
938
|
+
if (from===MATRIX && to===NDC) {
|
|
939
|
+
const f=m.fromFrame;
|
|
940
|
+
return _worldToNDC(out,f[0]*px+f[4]*py+f[8]*pz+f[12],
|
|
941
|
+
f[1]*px+f[5]*py+f[9]*pz+f[13],
|
|
942
|
+
f[2]*px+f[6]*py+f[10]*pz+f[14],_ensurePV(m));
|
|
1060
943
|
}
|
|
1061
|
-
if (from
|
|
1062
|
-
_ndcToWorld(out,
|
|
1063
|
-
|
|
1064
|
-
return mat4MulPoint(out, m.toFrameInv, wx,wy,wz);
|
|
944
|
+
if (from===NDC && to===MATRIX) {
|
|
945
|
+
_ndcToWorld(out,px,py,pz,m.mat4PVInv);
|
|
946
|
+
return mat4MulPoint(out,m.toFrameInv,out[0],out[1],out[2]);
|
|
1065
947
|
}
|
|
1066
948
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
fz=f[2]*px+f[6]*py+f[10]*pz+f[14];
|
|
1073
|
-
return mat4MulPoint(out, m.toFrameInv, fx,fy,fz);
|
|
949
|
+
if (from===MATRIX && to===MATRIX) {
|
|
950
|
+
const f=m.fromFrame;
|
|
951
|
+
return mat4MulPoint(out,m.toFrameInv,f[0]*px+f[4]*py+f[8]*pz+f[12],
|
|
952
|
+
f[1]*px+f[5]*py+f[9]*pz+f[13],
|
|
953
|
+
f[2]*px+f[6]*py+f[10]*pz+f[14]);
|
|
1074
954
|
}
|
|
1075
955
|
|
|
1076
|
-
// Fallback
|
|
1077
956
|
out[0]=px; out[1]=py; out[2]=pz;
|
|
1078
957
|
return out;
|
|
1079
958
|
}
|
|
1080
959
|
|
|
1081
|
-
// ── Direction
|
|
960
|
+
// ── Direction helpers ────────────────────────────────────────────────────
|
|
961
|
+
//
|
|
962
|
+
// Directions use only the linear 3×3 block — no translation, no w-divide.
|
|
963
|
+
// The signed vp[2]/vp[3] carries the y-convention automatically.
|
|
964
|
+
//
|
|
1082
965
|
|
|
1083
|
-
/** Apply the 3×3 linear part of a mat4 (rotation/scale, no translation). */
|
|
1084
966
|
function _applyDir(out, m, dx, dy, dz) {
|
|
1085
967
|
out[0]=m[0]*dx+m[4]*dy+m[8]*dz;
|
|
1086
968
|
out[1]=m[1]*dx+m[5]*dy+m[9]*dz;
|
|
@@ -1089,157 +971,123 @@ function _applyDir(out, m, dx, dy, dz) {
|
|
|
1089
971
|
}
|
|
1090
972
|
|
|
1091
973
|
function _worldToScreenDir(out, dx, dy, dz, proj, view, vpW, vpH, ndcZMin) {
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
// NDC→screen scale (direction, no offset).
|
|
1100
|
-
out[0]=cx*vpW*0.5; out[1]=-cy*vpH*0.5;
|
|
1101
|
-
out[2]=cz*(1-ndcZMin)*0.5;
|
|
974
|
+
const vx=view[0]*dx+view[4]*dy+view[8]*dz,
|
|
975
|
+
vy=view[1]*dx+view[5]*dy+view[9]*dz,
|
|
976
|
+
vz=view[2]*dx+view[6]*dy+view[10]*dz;
|
|
977
|
+
// vpH is signed — negative flips y component automatically.
|
|
978
|
+
out[0]=(proj[0]*vx+proj[4]*vy+proj[8]*vz)*vpW*0.5;
|
|
979
|
+
out[1]=(proj[1]*vx+proj[5]*vy+proj[9]*vz)*vpH*0.5;
|
|
980
|
+
out[2]=(proj[2]*vx+proj[6]*vy+proj[10]*vz)*(1-ndcZMin)*0.5;
|
|
1102
981
|
return out;
|
|
1103
982
|
}
|
|
1104
983
|
|
|
1105
|
-
function _screenToWorldDir(out, dx, dy, dz, proj,
|
|
1106
|
-
//
|
|
1107
|
-
|
|
1108
|
-
const nz=dz/((1-ndcZMin)*0.5);
|
|
1109
|
-
// NDC direction → eye direction (inverse projection, linear only).
|
|
1110
|
-
const ex=nx/proj[0], ey=ny/proj[5], ez=nz;
|
|
1111
|
-
// Eye direction → world direction.
|
|
1112
|
-
_applyDir(out, eMatrix, ex, ey, ez);
|
|
984
|
+
function _screenToWorldDir(out, dx, dy, dz, proj, eye, vpW, vpH, ndcZMin) {
|
|
985
|
+
// Inverse of _worldToScreenDir; signed vpW/vpH cancel the y-flip.
|
|
986
|
+
_applyDir(out, eye, dx/(vpW*0.5)/proj[0], dy/(vpH*0.5)/proj[5], dz/((1-ndcZMin)*0.5));
|
|
1113
987
|
return out;
|
|
1114
988
|
}
|
|
1115
989
|
|
|
1116
990
|
function _screenToNDCDir(out, dx, dy, dz, vpW, vpH, ndcZMin) {
|
|
1117
|
-
out[0]=dx/(vpW*0.5); out[1]
|
|
1118
|
-
out[2]=dz/((1-ndcZMin)*0.5);
|
|
991
|
+
out[0]=dx/(vpW*0.5); out[1]=dy/(vpH*0.5); out[2]=dz/((1-ndcZMin)*0.5);
|
|
1119
992
|
return out;
|
|
1120
993
|
}
|
|
1121
994
|
|
|
1122
995
|
function _ndcToScreenDir(out, dx, dy, dz, vpW, vpH, ndcZMin) {
|
|
1123
|
-
out[0]=dx*vpW*0.5; out[1]
|
|
1124
|
-
out[2]=dz*(1-ndcZMin)*0.5;
|
|
996
|
+
out[0]=dx*vpW*0.5; out[1]=dy*vpH*0.5; out[2]=dz*(1-ndcZMin)*0.5;
|
|
1125
997
|
return out;
|
|
1126
998
|
}
|
|
1127
999
|
|
|
1128
1000
|
/**
|
|
1129
1001
|
* Map a direction between named coordinate spaces.
|
|
1130
|
-
* Same bag contract as mapLocation.
|
|
1002
|
+
* Same bag and viewport contract as mapLocation.
|
|
1003
|
+
*
|
|
1004
|
+
* @param {number[]} out 3-element destination.
|
|
1005
|
+
* @param {number} dx,dy,dz Input direction.
|
|
1006
|
+
* @param {string} from Source space.
|
|
1007
|
+
* @param {string} to Destination space.
|
|
1008
|
+
* @param {object} m Matrices bag — see module header.
|
|
1009
|
+
* @param {number[]} vp Viewport [x, y, w, h]; sign of h encodes screen-y direction.
|
|
1010
|
+
* @param {number} ndcZMin WEBGL (−1) or WEBGPU (0).
|
|
1011
|
+
* @returns {number[]} out
|
|
1131
1012
|
*/
|
|
1132
1013
|
function mapDirection(out, dx, dy, dz, from, to, m, vp, ndcZMin) {
|
|
1133
|
-
const vpW
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
if (from
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
return
|
|
1142
|
-
if (from
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
return _screenToNDCDir(out, dx,dy,dz, vpW, vpH, ndcZMin);
|
|
1148
|
-
if (from === NDC && to === SCREEN)
|
|
1149
|
-
return _ndcToScreenDir(out, dx,dy,dz, vpW, vpH, ndcZMin);
|
|
1150
|
-
|
|
1151
|
-
// WORLD ↔ NDC
|
|
1152
|
-
if (from === WORLD && to === NDC) {
|
|
1153
|
-
_worldToScreenDir(out, dx,dy,dz, m.pMatrix, m.vMatrix, vpW, vpH, ndcZMin);
|
|
1154
|
-
const sx=out[0],sy=out[1],sz=out[2];
|
|
1155
|
-
return _screenToNDCDir(out, sx,sy,sz, vpW, vpH, ndcZMin);
|
|
1014
|
+
const vpW=vp[2], vpH=vp[3]; // signed — carry y-convention through all helpers
|
|
1015
|
+
|
|
1016
|
+
if (from===EYE && to===WORLD) return _applyDir(out,m.mat4Eye, dx,dy,dz);
|
|
1017
|
+
if (from===WORLD && to===EYE) return _applyDir(out,m.mat4View,dx,dy,dz);
|
|
1018
|
+
|
|
1019
|
+
if (from===WORLD && to===SCREEN) return _worldToScreenDir(out,dx,dy,dz,m.mat4Proj,m.mat4View,vpW,vpH,ndcZMin);
|
|
1020
|
+
if (from===SCREEN && to===WORLD) return _screenToWorldDir(out,dx,dy,dz,m.mat4Proj,m.mat4Eye, vpW,vpH,ndcZMin);
|
|
1021
|
+
|
|
1022
|
+
if (from===SCREEN && to===NDC) return _screenToNDCDir(out,dx,dy,dz,vpW,vpH,ndcZMin);
|
|
1023
|
+
if (from===NDC && to===SCREEN) return _ndcToScreenDir(out,dx,dy,dz,vpW,vpH,ndcZMin);
|
|
1024
|
+
|
|
1025
|
+
if (from===WORLD && to===NDC) {
|
|
1026
|
+
_worldToScreenDir(out,dx,dy,dz,m.mat4Proj,m.mat4View,vpW,vpH,ndcZMin);
|
|
1027
|
+
return _screenToNDCDir(out,out[0],out[1],out[2],vpW,vpH,ndcZMin);
|
|
1156
1028
|
}
|
|
1157
|
-
if (from
|
|
1158
|
-
_ndcToScreenDir(out,
|
|
1159
|
-
|
|
1160
|
-
return _screenToWorldDir(out, sx,sy,sz, m.pMatrix, m.eMatrix, vpW, vpH, ndcZMin);
|
|
1029
|
+
if (from===NDC && to===WORLD) {
|
|
1030
|
+
_ndcToScreenDir(out,dx,dy,dz,vpW,vpH,ndcZMin);
|
|
1031
|
+
return _screenToWorldDir(out,out[0],out[1],out[2],m.mat4Proj,m.mat4Eye,vpW,vpH,ndcZMin);
|
|
1161
1032
|
}
|
|
1162
1033
|
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
const wx=out[0],wy=out[1],wz=out[2];
|
|
1167
|
-
return _worldToScreenDir(out, wx,wy,wz, m.pMatrix, m.vMatrix, vpW, vpH, ndcZMin);
|
|
1034
|
+
if (from===EYE && to===SCREEN) {
|
|
1035
|
+
_applyDir(out,m.mat4Eye,dx,dy,dz);
|
|
1036
|
+
return _worldToScreenDir(out,out[0],out[1],out[2],m.mat4Proj,m.mat4View,vpW,vpH,ndcZMin);
|
|
1168
1037
|
}
|
|
1169
|
-
if (from
|
|
1170
|
-
_screenToWorldDir(out,
|
|
1171
|
-
|
|
1172
|
-
return _applyDir(out, m.vMatrix, wx,wy,wz);
|
|
1038
|
+
if (from===SCREEN && to===EYE) {
|
|
1039
|
+
_screenToWorldDir(out,dx,dy,dz,m.mat4Proj,m.mat4Eye,vpW,vpH,ndcZMin);
|
|
1040
|
+
return _applyDir(out,m.mat4View,out[0],out[1],out[2]);
|
|
1173
1041
|
}
|
|
1174
1042
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
_worldToScreenDir(out, wx,wy,wz, m.pMatrix, m.vMatrix, vpW, vpH, ndcZMin);
|
|
1180
|
-
const sx=out[0],sy=out[1],sz=out[2];
|
|
1181
|
-
return _screenToNDCDir(out, sx,sy,sz, vpW, vpH, ndcZMin);
|
|
1043
|
+
if (from===EYE && to===NDC) {
|
|
1044
|
+
_applyDir(out,m.mat4Eye,dx,dy,dz);
|
|
1045
|
+
_worldToScreenDir(out,out[0],out[1],out[2],m.mat4Proj,m.mat4View,vpW,vpH,ndcZMin);
|
|
1046
|
+
return _screenToNDCDir(out,out[0],out[1],out[2],vpW,vpH,ndcZMin);
|
|
1182
1047
|
}
|
|
1183
|
-
if (from
|
|
1184
|
-
_ndcToScreenDir(out,
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
const wx=out[0],wy=out[1],wz=out[2];
|
|
1188
|
-
return _applyDir(out, m.vMatrix, wx,wy,wz);
|
|
1048
|
+
if (from===NDC && to===EYE) {
|
|
1049
|
+
_ndcToScreenDir(out,dx,dy,dz,vpW,vpH,ndcZMin);
|
|
1050
|
+
_screenToWorldDir(out,out[0],out[1],out[2],m.mat4Proj,m.mat4Eye,vpW,vpH,ndcZMin);
|
|
1051
|
+
return _applyDir(out,m.mat4View,out[0],out[1],out[2]);
|
|
1189
1052
|
}
|
|
1190
1053
|
|
|
1191
|
-
|
|
1192
|
-
if (from
|
|
1193
|
-
if (from === WORLD && to === MATRIX) return _applyDir(out, m.toFrameInv, dx,dy,dz);
|
|
1054
|
+
if (from===MATRIX && to===WORLD) return _applyDir(out,m.fromFrame, dx,dy,dz);
|
|
1055
|
+
if (from===WORLD && to===MATRIX) return _applyDir(out,m.toFrameInv,dx,dy,dz);
|
|
1194
1056
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
_applyDir(out,
|
|
1198
|
-
const wx=out[0],wy=out[1],wz=out[2];
|
|
1199
|
-
return _applyDir(out, m.vMatrix, wx,wy,wz);
|
|
1057
|
+
if (from===MATRIX && to===EYE) {
|
|
1058
|
+
_applyDir(out,m.fromFrame,dx,dy,dz);
|
|
1059
|
+
return _applyDir(out,m.mat4View,out[0],out[1],out[2]);
|
|
1200
1060
|
}
|
|
1201
|
-
if (from
|
|
1202
|
-
_applyDir(out,
|
|
1203
|
-
|
|
1204
|
-
return _applyDir(out, m.toFrameInv, wx,wy,wz);
|
|
1061
|
+
if (from===EYE && to===MATRIX) {
|
|
1062
|
+
_applyDir(out,m.mat4Eye,dx,dy,dz);
|
|
1063
|
+
return _applyDir(out,m.toFrameInv,out[0],out[1],out[2]);
|
|
1205
1064
|
}
|
|
1206
1065
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
const wx=out[0],wy=out[1],wz=out[2];
|
|
1211
|
-
return _worldToScreenDir(out, wx,wy,wz, m.pMatrix, m.vMatrix, vpW, vpH, ndcZMin);
|
|
1066
|
+
if (from===MATRIX && to===SCREEN) {
|
|
1067
|
+
_applyDir(out,m.fromFrame,dx,dy,dz);
|
|
1068
|
+
return _worldToScreenDir(out,out[0],out[1],out[2],m.mat4Proj,m.mat4View,vpW,vpH,ndcZMin);
|
|
1212
1069
|
}
|
|
1213
|
-
if (from
|
|
1214
|
-
_screenToWorldDir(out,
|
|
1215
|
-
|
|
1216
|
-
return _applyDir(out, m.toFrameInv, wx,wy,wz);
|
|
1070
|
+
if (from===SCREEN && to===MATRIX) {
|
|
1071
|
+
_screenToWorldDir(out,dx,dy,dz,m.mat4Proj,m.mat4Eye,vpW,vpH,ndcZMin);
|
|
1072
|
+
return _applyDir(out,m.toFrameInv,out[0],out[1],out[2]);
|
|
1217
1073
|
}
|
|
1218
1074
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
_worldToScreenDir(out, wx,wy,wz, m.pMatrix, m.vMatrix, vpW, vpH, ndcZMin);
|
|
1224
|
-
const sx=out[0],sy=out[1],sz=out[2];
|
|
1225
|
-
return _screenToNDCDir(out, sx,sy,sz, vpW, vpH, ndcZMin);
|
|
1075
|
+
if (from===MATRIX && to===NDC) {
|
|
1076
|
+
_applyDir(out,m.fromFrame,dx,dy,dz);
|
|
1077
|
+
_worldToScreenDir(out,out[0],out[1],out[2],m.mat4Proj,m.mat4View,vpW,vpH,ndcZMin);
|
|
1078
|
+
return _screenToNDCDir(out,out[0],out[1],out[2],vpW,vpH,ndcZMin);
|
|
1226
1079
|
}
|
|
1227
|
-
if (from
|
|
1228
|
-
_ndcToScreenDir(out,
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
const wx=out[0],wy=out[1],wz=out[2];
|
|
1232
|
-
return _applyDir(out, m.toFrameInv, wx,wy,wz);
|
|
1080
|
+
if (from===NDC && to===MATRIX) {
|
|
1081
|
+
_ndcToScreenDir(out,dx,dy,dz,vpW,vpH,ndcZMin);
|
|
1082
|
+
_screenToWorldDir(out,out[0],out[1],out[2],m.mat4Proj,m.mat4Eye,vpW,vpH,ndcZMin);
|
|
1083
|
+
return _applyDir(out,m.toFrameInv,out[0],out[1],out[2]);
|
|
1233
1084
|
}
|
|
1234
1085
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
_applyDir(out,
|
|
1238
|
-
const wx=out[0],wy=out[1],wz=out[2];
|
|
1239
|
-
return _applyDir(out, m.toFrameInv, wx,wy,wz);
|
|
1086
|
+
if (from===MATRIX && to===MATRIX) {
|
|
1087
|
+
_applyDir(out,m.fromFrame,dx,dy,dz);
|
|
1088
|
+
return _applyDir(out,m.toFrameInv,out[0],out[1],out[2]);
|
|
1240
1089
|
}
|
|
1241
1090
|
|
|
1242
|
-
// Fallback
|
|
1243
1091
|
out[0]=dx; out[1]=dy; out[2]=dz;
|
|
1244
1092
|
return out;
|
|
1245
1093
|
}
|
|
@@ -1250,16 +1098,15 @@ function mapDirection(out, dx, dy, dz, from, to, m, vp, ndcZMin) {
|
|
|
1250
1098
|
|
|
1251
1099
|
/**
|
|
1252
1100
|
* World-units-per-pixel at a given eye-space Z depth.
|
|
1253
|
-
* @param {ArrayLike<number>} proj
|
|
1254
|
-
* @param {number}
|
|
1255
|
-
* @param {number}
|
|
1256
|
-
* @param {number}
|
|
1101
|
+
* @param {ArrayLike<number>} proj Projection mat4.
|
|
1102
|
+
* @param {number} vpH Viewport height in pixels (positive).
|
|
1103
|
+
* @param {number} eyeZ Eye-space Z — negative means in front of camera.
|
|
1104
|
+
* @param {number} ndcZMin WEBGL (−1) or WEBGPU (0).
|
|
1257
1105
|
*/
|
|
1258
1106
|
function pixelRatio(proj, vpH, eyeZ, ndcZMin) {
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
return 2 * Math.abs(eyeZ) * Math.tan(projFov(proj) / 2) / vpH;
|
|
1107
|
+
return projIsOrtho(proj)
|
|
1108
|
+
? Math.abs(projTop(proj,ndcZMin)-projBottom(proj,ndcZMin)) / vpH
|
|
1109
|
+
: 2*Math.abs(eyeZ)*Math.tan(projFov(proj)/2) / vpH;
|
|
1263
1110
|
}
|
|
1264
1111
|
|
|
1265
1112
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -1267,40 +1114,35 @@ function pixelRatio(proj, vpH, eyeZ, ndcZMin) {
|
|
|
1267
1114
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1268
1115
|
|
|
1269
1116
|
/**
|
|
1270
|
-
*
|
|
1117
|
+
* Mutate a projection matrix in-place so that the pixel at (px, py) maps to
|
|
1118
|
+
* the full NDC square — making a 1×1 FBO render contain exactly that pixel.
|
|
1119
|
+
*
|
|
1120
|
+
* Premultiplies by M_pick (column-major, rows 2 and 3 unchanged):
|
|
1271
1121
|
*
|
|
1272
|
-
*
|
|
1273
|
-
*
|
|
1274
|
-
*
|
|
1122
|
+
* ┌ sx 0 0 tx ┐ sx = |vp[2]|, sy = |vp[3]|
|
|
1123
|
+
* │ 0 sy 0 ty │ cx = ((px−vp[0])/vp[2])·2 − 1 (NDC x of pixel centre)
|
|
1124
|
+
* │ 0 0 1 0 │ cy = ((py−vp[1])/vp[3])·2 − 1 (NDC y, sign-aware)
|
|
1125
|
+
* └ 0 0 0 1 ┘ tx = −cx·sx, ty = −cy·sy
|
|
1275
1126
|
*
|
|
1276
|
-
* M_pick
|
|
1277
|
-
*
|
|
1278
|
-
*
|
|
1279
|
-
* [ 0 0 1 0 ] cy = NDC Y of pixel centre = 1 − 2*(py+0.5)/H
|
|
1280
|
-
* [ 0 0 0 1 ] tx = −cx·W, ty = −cy·H
|
|
1127
|
+
* Result: P_pick = M_pick · P_original.
|
|
1128
|
+
* The viewport sign convention (vp[3] < 0 for screen y-down) is preserved
|
|
1129
|
+
* automatically through cx/cy — no separate flip needed.
|
|
1281
1130
|
*
|
|
1282
1131
|
* @param {Float32Array} proj Projection mat4 — mutated in place.
|
|
1283
|
-
* @param {number} px Query X
|
|
1284
|
-
* @param {number} py Query Y
|
|
1285
|
-
* @param {number}
|
|
1286
|
-
* @param {number} H Canvas height (CSS pixels).
|
|
1287
|
-
* @returns {Float32Array} proj (same reference)
|
|
1132
|
+
* @param {number} px Query pixel X in screen coordinates.
|
|
1133
|
+
* @param {number} py Query pixel Y in screen coordinates.
|
|
1134
|
+
* @param {number[]} vp Viewport [x, y, w, h]; same signed convention as mapLocation.
|
|
1288
1135
|
*/
|
|
1289
|
-
function mat4Pick(proj, px, py,
|
|
1290
|
-
const cx
|
|
1291
|
-
const cy
|
|
1292
|
-
const sx =
|
|
1293
|
-
const sy
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
const b = proj[j * 4 + 1];
|
|
1299
|
-
const d = proj[j * 4 + 3];
|
|
1300
|
-
proj[j * 4] = sx * a + tx * d;
|
|
1301
|
-
proj[j * 4 + 1] = sy * b + ty * d;
|
|
1136
|
+
function mat4Pick(proj, px, py, vp) {
|
|
1137
|
+
const cx=((px-vp[0])/vp[2])*2-1;
|
|
1138
|
+
const cy=((py-vp[1])/vp[3])*2-1;
|
|
1139
|
+
const sx=Math.abs(vp[2]), sy=Math.abs(vp[3]);
|
|
1140
|
+
const tx=-cx*sx, ty=-cy*sy;
|
|
1141
|
+
for (let j=0; j<4; j++) {
|
|
1142
|
+
const a=proj[j*4], b=proj[j*4+1], d=proj[j*4+3];
|
|
1143
|
+
proj[j*4] = sx*a + tx*d;
|
|
1144
|
+
proj[j*4+1] = sy*b + ty*d;
|
|
1302
1145
|
}
|
|
1303
|
-
return proj;
|
|
1304
1146
|
}
|
|
1305
1147
|
|
|
1306
1148
|
/**
|
|
@@ -2445,5 +2287,5 @@ function boxVisibility(planes, x0, y0, z0, x1, y1, z1) {
|
|
|
2445
2287
|
return allIn ? VISIBLE : SEMIVISIBLE;
|
|
2446
2288
|
}
|
|
2447
2289
|
|
|
2448
|
-
export { CameraTrack, EYE, INVISIBLE, MATRIX, MODEL, NDC, ORIGIN, PLANE_BOTTOM, PLANE_FAR, PLANE_LEFT, PLANE_NEAR, PLANE_RIGHT, PLANE_TOP, PoseTrack, SCREEN, SEMIVISIBLE, VISIBLE, WEBGL, WEBGPU, WORLD, _i, _j, _k, boxVisibility, distanceToPlane, frustumPlanes, hermiteVec3, i, j, k, lerpVec3, mapDirection, mapLocation, mat3Direction, mat3NormalFromMat4, mat4Bias, mat4Eye, mat4FromBasis, mat4FromScale, mat4FromTRS, mat4FromTranslation, mat4Frustum, mat4Invert, mat4Location, mat4MV, mat4Mul, mat4MulDir, mat4MulPoint, mat4Ortho, mat4PV, mat4Perspective, mat4Pick, mat4Reflect, mat4ToRotation, mat4ToScale, mat4ToTransform, mat4ToTranslation,
|
|
2290
|
+
export { CameraTrack, EYE, INVISIBLE, MATRIX, MODEL, NDC, ORIGIN, PLANE_BOTTOM, PLANE_FAR, PLANE_LEFT, PLANE_NEAR, PLANE_RIGHT, PLANE_TOP, PoseTrack, SCREEN, SEMIVISIBLE, VISIBLE, WEBGL, WEBGPU, WORLD, _i, _j, _k, boxVisibility, distanceToPlane, frustumPlanes, hermiteVec3, i, j, k, lerpVec3, mapDirection, mapLocation, mat3Direction, mat3NormalFromMat4, mat4Bias, mat4Eye, mat4FromBasis, mat4FromScale, mat4FromTRS, mat4FromTranslation, mat4Frustum, mat4Invert, mat4Location, mat4MV, mat4Mul, mat4MulDir, mat4MulPoint, mat4Ortho, mat4PV, mat4Perspective, mat4Pick, mat4Reflect, mat4ToRotation, mat4ToScale, mat4ToTransform, mat4ToTranslation, mat4View, pixelRatio, pointVisibility, projBottom, projFar, projFov, projHfov, projIsOrtho, projLeft, projNear, projRight, projTop, qCopy, qDot, qFromAxisAngle, qFromLookDir, qFromMat4, qFromRotMat3x3, qMul, qNegate, qNlerp, qNormalize, qSet, qSlerp, qToMat4, quatToAxisAngle, sphereVisibility, transformToMat4 };
|
|
2449
2291
|
//# sourceMappingURL=index.js.map
|