-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathh3du-math.js
4657 lines (4634 loc) · 214 KB
/
h3du-math.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
Any copyright to this file is released to the Public Domain.
In case this is not possible, this file is also licensed under the Unlicense: https://unlicense.org/
*/
/**
* A collection of math functions for working
* with vectors, matrices, quaternions, and other
* mathematical objects of interest to three-dimensional graphics programming.<p>
* <a id=Vectors></a>
* ## Vectors
* A vector is a line segment pointing in a certain _direction_ in space and
* having a certain _length_ and an unspecified starting point.
* A particular vector can instead be treated as describing a position
* (by pointing to that position from an _origin_ (0,0,0)), or a color.
* In `MathUtil`, vectors are stored in arrays of numbers (usually
* three or four numbers), and functions dealing with vectors begin
* with "vec".
* If a 4-element vector describes a position or direction, the elements
* are given as X, Y, Z, and W, in that order.
* If a 4-element vector describes a color, the elements are given as red, green,
* blue, and alpha, in that order (where each element ranges from 0-1).
* If a 3D _direction_ is used in a 4-element vector function (one beginning with "vec4"),
* use 0 as the fourth element. If a 3D _position_ (point) is used in a 4-element vector
* function, the fourth element is generally 1. (If the
* fourth element is anything other than 0, the vector is in _homogeneous
* coordinates_, where the 3D position equals the first three elements divided
* by the fourth.)
* A _unit vector_ is a vector with a length of 1. (A vector's _length_, or _norm_, is the square root
* of the sum of the squares of its components.) A vector can be "normalized" to
* a unit vector by dividing each of its components by its length (doing so won't change
* the vector's direction). The following functions normalize vectors and find their length: {@link MathUtil.vec3normalize} converts a 3-element vector to a unit vector; {@link MathUtil.vec4normalize} converts a 4-element vector to a unit vector; {@link MathUtil.vec3length} finds a 3-element vector's length; {@link MathUtil.vec4length} finds a 4-element vector's length. Note that due to rounding error, normalizing a vector with a `MathUtil` method might not necessarily result in a vector with a length of 1.
* <a id=Matrices></a>
* ## Matrices
* A matrix is a rectangular array that can describe a
* transformation from one coordinate system to another. Transformations
* that matrices can describe include translation (shifting), scaling, and rotation.
* Functions dealing with matrices begin with "mat".
* A 3 × 3 or 4 × 4 matrix has 9 or 16 elements, respectively. In mathematical publications,
* matrices are often notated in column-major order, in which each
* element of the matrix is placed in columns as opposed to rows, as in the following example:
* <math>
* <mfenced open="[" close="]">
* <mtable>
* <mtr>
* <mtd><mi>matrix[0]</mi></mtd>
* <mtd><mi>matrix[4]</mi></mtd>
* <mtd><mi>matrix[8]</mi></mtd>
* <mtd><mi>matrix[12]</mi></mtd>
* </mtr>
* <mtr>
* <mtd><mi>matrix[1]</mi></mtd>
* <mtd><mi>matrix[5]</mi></mtd>
* <mtd><mi>matrix[9]</mi></mtd>
* <mtd><mi>matrix[13]</mi></mtd>
* </mtr>
* <mtr>
* <mtd><mi>matrix[2]</mi></mtd>
* <mtd><mi>matrix[6]</mi></mtd>
* <mtd><mi>matrix[10]</mi></mtd>
* <mtd><mi>matrix[14]</mi></mtd>
* </mtr>
* <mtr>
* <mtd><mi>matrix[3]</mi></mtd>
* <mtd><mi>matrix[7]</mi></mtd>
* <mtd><mi>matrix[11]</mi></mtd>
* <mtd><mi>matrix[15]</mi></mtd>
* </mtr>
* </mtable>
* </mfenced>
* </math>
* The numbers in brackets in the matrix above are the zero-based indices
* into the matrix arrays passed to `MathUtil`'s matrix methods.
* For 3 × 3 matrices, the elements are arranged in the following order:
* <math>
* <mfenced open="[" close="]">
* <mtable>
* <mtr>
* <mtd><mi>matrix[0]</mi></mtd>
* <mtd><mi>matrix[3]</mi></mtd>
* <mtd><mi>matrix[6]</mi></mtd>
* </mtr>
* <mtr>
* <mtd><mi>matrix[1]</mi></mtd>
* <mtd><mi>matrix[4]</mi></mtd>
* <mtd><mi>matrix[7]</mi></mtd>
* </mtr>
* <mtr>
* <mtd><mi>matrix[2]</mi></mtd>
* <mtd><mi>matrix[5]</mi></mtd>
* <mtd><mi>matrix[8]</mi></mtd>
* </mtr>
* </mtable>
* </mfenced>
* </math>
* <b>A Matrix Transforms Between Coordinate Systems:</b> A transformed 3D coordinate system is made up of an x-, y-, and z-axes, and a center of the coordinate system. These are four 3-element vectors that describe how the three axes and the center map to the new coordinate system in relation to the old coordinate system.
* The following depiction of a 4 × 4 matrix illustrates the meaning of each of its elements. To keep things
* simple, this matrix's transformation is one that keeps straight lines straight and parallel lines parallel.
* <math>
* <mfenced open="[" close="]">
* <mtable>
* <mtr>
* <mtd><mi>[0] x-axis X</mi></mtd>
* <mtd><mi>[4] y-axis X</mi></mtd>
* <mtd><mi>[8] z-axis X</mi></mtd>
* <mtd><mi>[12] Center X</mi></mtd>
* </mtr>
* <mtr>
* <mtd><mi>[1] x-axis Y</mi></mtd>
* <mtd><mi>[5] y-axis Y</mi></mtd>
* <mtd><mi>[9] z-axis Y</mi></mtd>
* <mtd><mi>[13] Center Y</mi></mtd>
* </mtr>
* <mtr>
* <mtd><mi>[2] x-axis Z</mi></mtd>
* <mtd><mi>[6] y-axis Z</mi></mtd>
* <mtd><mi>[10] z-axis Z</mi></mtd>
* <mtd><mi>[14] Center Z</mi></mtd>
* </mtr>
* <mtr>
* <mtd><mi>[3] 0</mi></mtd>
* <mtd><mi>[7] 0</mi></mtd>
* <mtd><mi>[11] 0</mi></mtd>
* <mtd><mi>[15] 1</mi></mtd>
* </mtr>
* </mtable>
* </mfenced>
* </math>
* The following is an example of a transformation matrix.
* <math>
* <mfenced open="[" close="]">
* <mtable>
* <mtr>
* <mtd><mn>1</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>2</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mn>0</mn></mtd>
* <mtd><mi>0.5</mi></mtd>
* <mtd><mo>-0.866025</mtd>
* <mtd><mn>3</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mn>0</mn></mtd>
* <mtd><mi>0.866025</mtd>
* <mtd><mi>0.5</mtd>
* <mtd><mn>4</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mn>1</mn></mtd>
* </mtr>
* </mtable>
* </mfenced>
* </math>
* Here, the first column shows an x-axis vector at (1, 0, 0),
* the second column shows a y-axis vector at (0, 0.5, 0.866025),
* the third column shows a z-axis vector at (0, -0.866025, 0.5),
* and the fourth column centers the coordinate system at (2, 3, 4).
* Provided the matrix can be inverted (see the documentation for mat4invert), the three axis vectors are
* _basis vectors_ of the coordinate system.
* *Why a 4 × 4 matrix?** A matrix can describe _linear transformations_ from one vector in space
* to another. These transformations, which include [**scaling**](#Scaling),
* [**rotation**](#Rotation), and shearing, can change where a vector points _at_,
* but not where it points _from_. It's enough to use a 3 × 3 matrix to describe
* linear transformations in 3D space.
* But certain other transformations, such as [**translation**](#Translation) and
* [**perspective**](#Projective_Transformations), are common in 3D computer graphics.
* To describe translation and perspective in 3D, the 3 × 3 matrix must be
* augmented by an additional row and column, turning it into a 4 × 4 matrix.
* A 4 × 4 matrix can describe linear transformations in 4D space and
* transform 4-element vectors. A 4-element vector has four components:
* X, Y, Z, and W. If a 4-element vector represents a 3D point, these
* components are the point's _homogeneous coordinates_ (unless the
* vector's W is 0). To convert these coordinates back to 3D, divide
* X, Y, and Z by W. This is usually only required, however, if the
* matrix describes a perspective projection (see
* [**"Projective Transformations"**](#Projective_Transformations)).
* A similar situation applies in 2D between 2 × 2 and 3 × 3 matrices as it does
* in 3D between 3 × 3 and 4 × 4 matrices.
* *Transforming points.** The transformation formula multiplies a matrix by a 3D point to change that point's
* position:
* **a′**<sub>_x_</sub> = matrix[0] ⋅ **a**<sub>_x_</sub> + matrix[4] ⋅ **a**<sub>_y_</sub> + matrix[8] ⋅ **a**<sub>_z_</sub> + matrix[12] ⋅ **a**<sub>_w_</sub>
* **a′**<sub>_y_</sub> = matrix[1] ⋅ **a**<sub>_x_</sub> + matrix[5] ⋅ **a**<sub>_y_</sub> + matrix[9] ⋅ **a**<sub>_z_</sub> + matrix[13] ⋅ **a**<sub>_w_</sub>
* **a′**<sub>_z_</sub> = matrix[2] ⋅ **a**<sub>_x_</sub> + matrix[6] ⋅ **a**<sub>_y_</sub> + matrix[10] ⋅ **a**<sub>_z_</sub> + matrix[14] ⋅ **a**<sub>_w_</sub>
* **a′**<sub>_w_</sub> = matrix[3] ⋅ **a**<sub>_x_</sub> + matrix[7] ⋅ **a**<sub>_y_</sub> + matrix[11] ⋅ **a**<sub>_z_</sub> + matrix[15] ⋅ **a**<sub>_w_</sub>
* For more on why **a′**<sub>_w_</sub> appears here, see **"Why a 4 × 4 Matrix?"**, earlier. In each formula that follows, **a**<sub>_w_</sub> is assumed to be 1 (indicating a conventional 3D point).
* * Scaling.** Scaling changes an object's size.
* To create a scaling matrix, use [MathUtil.mat4scaled()]{@link MathUtil.mat4scaled},
* and specify the scaling factors for the x-, y-, and z-axes. Each point is multiplied by the scaling
* factors to change the object's size. For example, a Y-factor of 2 doubles an object's height.
* To multiply an existing matrix by a scaling, use
* [MathUtil.mat4scale()]{@link MathUtil.mat4scale}. This will put the scaling
* before the other transformations.
* Scaling uses the 1st, 6th, and 11th elements of the matrix as seen here:
* <math>
* <mfenced open="[" close="]">
* <mtable>
* <mtr>
* <mtd><mi>sx</mi></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mn>0</mn></mtd>
* <mtd><mi>sy</mi></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mi>sz</mi></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mn>1</mn></mtd>
* </mtr>
* </mtable>
* </mfenced>
* </math>
* where the x-coordinate is multiplied by `sx`, the y-coordinate is multiplied by `sy`, and
* the z-coordinate is multiplied by `sz`.
* The scaling formula would look like:
* **a′**<sub>_x_</sub> = sx ⋅ **a**<sub>_x_</sub> + 0 ⋅ **a**<sub>_y_</sub> + 0 ⋅ **a**<sub>_z_</sub> + 0
* **a′**<sub>_y_</sub> = 0 ⋅ **a**<sub>_x_</sub> + sy ⋅ **a**<sub>_y_</sub> + 0 ⋅ **a**<sub>_z_</sub> + 0
* **a′**<sub>_z_</sub> = 0 ⋅ **a**<sub>_x_</sub> + 0 ⋅ **a**<sub>_y_</sub> + sz ⋅ **a**<sub>_z_</sub> + 0
* **a′**<sub>_w_</sub> = 0 ⋅ **a**<sub>_x_</sub> + 0 ⋅ **a**<sub>_y_</sub> + 0 ⋅ **a**<sub>_z_</sub> + 1 = 1
* For example, we multiply the input x by `sx` to get the output x. If `sx` is 1, x
* remains unchanged. Likewise for y (`sy`) and z (`sz`).
* If `sx`, `sy`, or `sz` is -1, that coordinate is _reflected_ along the corresponding axis.
* If `sx`, `sy`, and `sz` are all 1, we have an _identity matrix_, where the input vector
* is equal to the output vector.
* When the transformed X, Y, or z-axis has a length other than 1, the coordinate
* system will be scaled up or down along that axis. The scalings given
* here will scale the lengths of the corresponding axes. For example,
* if `sx` is 2, the x-axis will be (2, 0, 0) and thus have a length of 2.
* **Translation.** A translation is a shifting of an object's position.
* To create a translation matrix, use [MathUtil.mat4translated()]{@link MathUtil.mat4translated},
* and specify the X-offset, the Y-offset, and the Z-offset. For example, an X-offset of 1 moves
* an object 1 unit to the right, and a Y offset of -1 moves it 1 unit down.
* To multiply an existing matrix by a translation, use
* [MathUtil.mat4translate()]{@link MathUtil.mat4translate}. This will put the translation
* before the other transformations. In a transformation matrix,
* translation effectively occurs after all other transformations such as scaling and rotation.
* It uses the 13th, 14th, and 15th elements of the matrix as seen here:
* <math>
* <mfenced open="[" close="]">
* <mtable>
* <mtr>
* <mtd><mn>1</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>tx</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>1</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>ty</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>1</mn></mtd>
* <mtd><mn>tz</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mn>1</mn></mtd>
* </mtr>
* </mtable>
* </mfenced>
* </math>
* where `tx` is added to the x-coordinate, `ty` is added to the y-coordinate, and
* `tz` is added to the z-coordinate. The transformation formulas would look like:
* **a′**<sub>_x_</sub> = 1 ⋅ **a**<sub>_x_</sub> + 0 ⋅ **a**<sub>_y_</sub> + 0 ⋅ **a**<sub>_z_</sub> + tx
* **a′**<sub>_y_</sub> = 0 ⋅ **a**<sub>_x_</sub> + 1 ⋅ **a**<sub>_y_</sub> + 0 ⋅ **a**<sub>_z_</sub> + ty
* **a′**<sub>_z_</sub> = 0 ⋅ **a**<sub>_x_</sub> + 0 ⋅ **a**<sub>_y_</sub> + 1 ⋅ **a**<sub>_z_</sub> + tz
* **a′**<sub>_w_</sub> = 0 ⋅ **a**<sub>_x_</sub> + 0 ⋅ **a**<sub>_y_</sub> + 0 ⋅ **a**<sub>_z_</sub> + 1 = 1
* For example, we add the input x and `tx` to get the output x. If `tx` is 0, x
* remains unchanged. Likewise for y (`ty`) and z (`tz`).
* *Rotation.** Rotation changes an object's orientation.
* To create a rotation matrix, use [MathUtil.mat4rotated()]{@link MathUtil.mat4rotated},
* and specify the angle (in degrees) to rotate, and the [**axis of rotation**](#Axis_of_Rotation). For example:
* Specifying `(45, [1, 0, 0])` means a 45-degree rotation of the point around the x-axis.
* Specifying `(80, [0, 2, 3])` means a 45-degree rotation of the point around the axis that
* starts at the origin (0, 0, 0) and points toward the point (0, 2, 3).
* When describing an axis of rotation, <code>[1, 0, 0]</code> is the x-axis,
* <code>[0, 1, 0]</code> is the y-axis, and <code>[0, 0, 1]</code> is the z-axis.
* To multiply an existing matrix by a rotation, use
* [MathUtil.mat4rotate()]{@link MathUtil.mat4rotate}. This will put the rotation
* before the other transformations.
* Given an angle of rotation, θ,
* the transformation matrix for rotating 3D points is as follows. (For a list of common
* sines and cosines, see the end of this section.)
* <figure>
* <math>
* <mfenced open="[" close="]">
* <mtable>
* <mtr>
* <mtd><mn>1</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mn>0</mn></mtd>
* <mtd><mi>cos</mi><mi>θ</mi></mtd>
* <mtd><mo>-</mo><mi>sin</mi><mi>θ</mi></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mn>0</mn></mtd>
* <mtd><mi>sin</mi><mi>θ</mi></mtd>
* <mtd><mi>cos</mi><mi>θ</mi></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mn>1</mn></mtd>
* </mtr>
* </mtable>
* </mfenced>
* </math>
* <figcaption>Rotation about the x-axis.</figcaption></figure>
* <figure>
* <math>
* <mfenced open="[" close="]">
* <mtable>
* <mtr>
* <mtd><mi>cos</mi><mi>θ</mi></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mi>sin</mi><mi>θ</mi></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>1</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mo>-</mo><mi>sin</mi><mi>θ</mi></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mi>cos</mi><mi>θ</mi></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mn>1</mn></mtd>
* </mtr>
* </mtable>
* </mfenced>
* </math>
* <figcaption>Rotation about the y-axis.</figcaption></figure>
* <figure>
* <math>
* <mfenced open="[" close="]">
* <mtable>
* <mtr>
* <mtd><mi>cos</mi><mi>θ</mi></mtd>
* <mtd><mo>-</mo><mi>sin</mi><mi>θ</mi></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mi>sin</mi><mi>θ</mi></mtd>
* <mtd><mi>cos</mi><mi>θ</mi></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>0</mn></mtd>
* <mtd><mn>1</mn></mtd>
* <mtd><mn>0</mn></mtd>
* </mtr>
* <mtr>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mi>0</mi></mtd>
* <mtd><mn>1</mn></mtd>
* </mtr>
* </mtable>
* </mfenced>
* </math>
* <figcaption>Rotation about the z-axis.</figcaption></figure>
* Note that:
* When we rotate a point about the x-axis, the x-coordinate is unchanged
* and the y- and z-coordinates are adjusted in the rotation. For rotations about the
* y-axis or the z-axis, the Y or z-coordinate, respectively, is likewise unchanged.
* If the axis of rotation points backward from the "eye", positive rotations mean
* counterclockwise rotation in right-handed coordinate systems. For example,
* 60 degrees about the axis means
* 60 degrees counterclockwise, and negative 60 degrees means 60 degrees
* clockwise.
* Rotating a point around an arbitrary axis of rotation is more complicated to describe.
* When describing an axis of rotation, <code>[1, 0, 0]</code> is the x-axis,
* <code>[0, 1, 0]</code> is the y-axis, and <code>[0, 0, 1]</code> is the z-axis.
* See [**"Rotation example"**](#Rotation_Example) for an illustration of a rotation
* transformation.
* Related functions:
* [MathUtil.mat4rotated()]{@link MathUtil.mat4rotated} -
* Returns a rotation matrix
* [MathUtil.mat4rotate()]{@link MathUtil.mat4rotate} -
* Multiplies a matrix by a translation.
* A list of common sines and cosines follows. Values
* shown with three decimal places are approximate.
* | | 0°| 22.5°| 30°| 45°| 60°| 67.5°| 90°| 112.5°| 120°| 135°| 150°| 157.5°| 180°|
* -------|---|------|----|----|----|------|----|------|-----|-----|-----|-------|-----|
* | sin | 0 | 0.383 | 0.5 | 0.707 | 0.866 | 0.924 | 1 | 0.924 | 0.866 | 0.707 | 0.5 | 0.383 | 0 |
* | cos | 1 | 0.924 | 0.866 | 0.707 | 0.5 | 0.383 | 0 | -0.383 | -0.5 | -0.707 | -0.866 | -0.924 | -1 |
* | | 180°| 202.5°| 210°| 225°| 240°| 247.5°| 270°| 292.5°| 300°| 315°| 330°| 337.5°| 360°|
* -------|---|------|----|----|----|------|----|------|-----|-----|-----|-------|-----|
* | sin | 0 | -0.383 | -0.5 | -0.707 | -0.866 | -0.924 | -1 | -0.924 | -0.866 | -0.707 | -0.5 | -0.383 | 0 |
* | cos | -1 | -0.924 | -0.866 | -0.707 | -0.5 | -0.383 | 0 | 0.383 | 0.5 | 0.707 | 0.866 | 0.924 | 1 |
* <a id=Matrix_Multiplication></a>
* ### Matrix Multiplication
* The order in which you do transforms is important. In general, scaling then translating is
* not the same as translating then scaling. Assuming your geometry is centered at the origin
* (0, 0, 0), you should create a transformation in this order:
* Call [`MathUtil.mat4identity()`]{@link MathUtil.mat4identity}, creating a matrix without a transformation.
* Do your translations if needed, using [`mat4translate()`]{@link MathUtil.mat4translate}.
* Do your rotations if needed, using [`mat4rotate()`]{@link MathUtil.mat4rotate}.
* Do your scalings if needed, using [`mat4scale()`]{@link MathUtil.mat4scale}.
* This way, the scalings and rotations will affect the object while it's still centered, and
* before the translations (shifts) take place.
* You can also multiply transforms using [MathUtil.mat4multiply()]{@link MathUtil.mat4multiply}.
* This takes two matrices and returns one combined matrix. The combined matrix will have the effect
* of doing the second matrix's transform, then the first matrix's transform.
* When two matrices are multiplied, the combined matrix will be such
* that the transformations they describe happen in reverse
* order. For example, if the first matrix (input matrix) describes a translation and the second
* matrix describes a scaling, the multiplied matrix will
* describe the effect of scaling then translation.
* Matrix multiplication is not commutative; the order of multiplying matrices is important.
* To get an insight of how matrix multiplication works, treat the second matrix as a group
* of column vectors (with the same number of rows as the number of columns in the
* first matrix). Multiplying the two matrices transforms these vectors to new ones in the
* same way as if the column vectors were transformed individually. (This also explains why there can
* be one or more column vectors in the second matrix and not just four in the case of a 4 × 4 matrix,
* and also why transforming a 4-element column vector is the same as multiplying a 4 × 4 matrix by a
* matrix with one column and four rows.*)
* This insight reveals a practical use of matrix multiplication: transforming four 4-element
* vectors at once using a single matrix operation involving two 4 × 4 matrices. After the
* matrix multiplication, each of the transformed vectors will be contained in one of the four columns
* of the output matrix.
* The methods `mat4multiply`, `mat4scale`, `mat4scaleInPlace`, `mat4translate`, and
* mat4rotate involve multiplying 4 × 4 matrices.
* Related functions:
* [MathUtil.mat4multiply()]{@link MathUtil.mat4multiply} -
* Multiplies two matrices
* \* Reading the [**tutorial by Dmitry Sokolov**](https://github.com/ssloy/tinyrenderer/wiki/Lesson-4:-Perspective-projection) led me to this useful insight.
* *Projective transformations.** In all the transformations described earlier, the last row in the transformation matrix is
* (0, 0, 0, 1). (Such transformations are called _affine transformations_, those that
* keep straight lines straight and parallel lines parallel.) However, this is not the case for
* some transformations in the `MathUtil` class.
* Transformations that don't necessarily preserve parallelism of lines are called _projective transformations_.
* An NxN matrix can describe certain projective transformations if it has one more row and one more column
* than the number of dimensions. For example, a 4 × 4 matrix can describe 3D projective transformations
* in the form of linear transformations on homogeneous coordinates (see
* [**"Why a 4 × 4 Matrix?"**](#Why_a_4x4_Matrix)). For a 3D projective transformation, the last row
* in the matrix is not necessarily (0, 0, 0, 1).
* One example of a projective transformation is found in a _perspective projection_ matrix,
* as returned by {@link MathUtil.mat4perspective} or {@link MathUtil.mat4frustum}. When a 4-element vector is transformed with this matrix, its W component is generated by setting it to the negative z-coordinate in _eye space_, or more specifically, as follows:
* **a′**<sub>_w_</sub> = 0 ⋅ **a**<sub>_x_</sub> + 0 ⋅ **a**<sub>_y_</sub> + -1 ⋅ **a**<sub>_z_</sub> + 0
* For more on perspective projections, see [_The "Camera" and Geometric Transforms_]{@tutorial camera}.
* Related functions:
* [MathUtil.mat4frustum()]{@link MathUtil.mat4frustum} -
* Returns a frustum matrix
* [MathUtil.mat4perspective()]{@link MathUtil.mat4perspective} -
* Returns a field-of-view perspective matrix
* ## Rotation Example
* As an example, say we rotate 60 degrees about the x-axis (`mat4rotated(60, 1, 0, 0)`,
* θ = 60°). First, we find the rotation formula for the x-axis:
* **a′**<sub>_x_</sub> = 1 ⋅ **a**<sub>_x_</sub> + 0 ⋅ **a**<sub>_y_</sub> + 0 ⋅ **a**<sub>_z_</sub> + 0
* **a′**<sub>_y_</sub> = 0 ⋅ **a**<sub>_x_</sub> + (cos θ) ⋅ **a**<sub>_y_</sub> + -(sin θ) ⋅ **a**<sub>_z_</sub> + 0
* **a′**<sub>_z_</sub> = 0 ⋅ **a**<sub>_x_</sub> + (sin θ) ⋅ **a**<sub>_y_</sub> + (cos θ) ⋅ **a**<sub>_z_</sub> + 0
* **a′**<sub>_w_</sub> = 0 ⋅ **a**<sub>_x_</sub> + 0 ⋅ **a**<sub>_y_</sub> + 0 ⋅ **a**<sub>_z_</sub> + 1 = 1
* We calculate <i>cos θ</i> as 0.5 and <i>sin θ</i> as about 0.866025.
* We plug those numbers into the rotation formula to get a formula for rotating a
* point 60 degrees about the x-axis.
* **a′**<sub>_x_</sub> = 1 ⋅ **a**<sub>_x_</sub> + 0 ⋅ **a**<sub>_y_</sub> + 0 ⋅ **a**<sub>_z_</sub> + 0 = **a**<sub>_x_</sub>
* **a′**<sub>_y_</sub> ~= 0 ⋅ **a**<sub>_x_</sub> + 0.5 ⋅ **a**<sub>_y_</sub> + -0.866025 ⋅ **a**<sub>_z_</sub> + 0
* **a′**<sub>_z_</sub> ~= 0 ⋅ **a**<sub>_x_</sub> + 0.866025 ⋅ **a**<sub>_y_</sub> + 0.5 ⋅ **a**<sub>_z_</sub> + 0
* **a′**<sub>_w_</sub> = 0 ⋅ **a**<sub>_x_</sub> + 0 ⋅ **a**<sub>_y_</sub> + 0 ⋅ **a**<sub>_z_</sub> + 1 = 1
* If a point is located at (10, 20, 30), the rotated point would now be:
* **a′**<sub>_x_</sub> = 1 ⋅ 10 + 0 ⋅ 20 + 0 ⋅ 30 + 0
* = 1 ⋅ 10
* = 10
* **a′**<sub>_y_</sub> ~= 0 ⋅ 10 + 0.5 ⋅ 20 + -0.866025 ⋅ 30 + 0
* ~= 0.5 ⋅ 20 + -0.866025 ⋅ 30
* ~= 10 + -25.98075
* ~= -15.98075
* **a′**<sub>_z_</sub> ~= 0 ⋅ 10 + 0.866025 ⋅ 20 + 0.5 ⋅ 30 + 0
* ~= 0.866025 ⋅ 20 + 0.5 ⋅ 30
* ~= 17.3205 + 15
* ~= 32.3205
* **a′**<sub>_w_</sub> = 0 ⋅ 10 + 0 ⋅ 20 + 0 ⋅ 30 + 1
* = 1
* So the rotated point would be at about (10, -15.98075, 32.3205).
* ## Describing Rotations
* Rotations in 3D space can be described in many ways, including
* quaternions, Tait-Bryan angles, and an angle and axis.
* <a id=Axis_of_Rotation></a>
* ### Axis of Rotation
* A rotation of vectors or points can be described using an _angle_
* and an _axis of rotation_, for example, in the {@link MathUtil.mat4rotate} method.
* An axis of rotation is a vector pointing in a certain direction. When a point (or vector)
* is rotated at any angle around this axis, the new point (or vector) will lie
* on the same plane as the previous point. The axis of rotation describes
* a vector that is perpendicular to that plane's surface (the plane's _normal_).
* Here are examples of an axis of rotation.
* The x-axis of rotation (upward or downward turn) is (1, 0, 0).
* The y-axis of rotation (leftward or rightward turn) is (0, 1, 0).
* The z-axis of rotation (side-by-side sway) is (0, 0, 1).
* While the axis of rotation points backward from the "eye", if the angle's value
* is positive and the [**coordinate system**](#Coordinate_Systems) is...
* ...right handed, then the angle runs counterclockwise.
* ...left handed, then the angle runs clockwise.
* While the axis of rotation points backward from the "eye", if the angle's value
* is negative, then the angle runs in the opposite direction.
* Vectors that point in the same direction (for example, vectors (1, 0, 0) and (2, 0, 0))
* describe the same axis of rotation.
* Unless stated otherwise, an axis of rotation passed to a `MathUtil`
* method need not be a [**unit vector**](#Unit_Vectors).
* ### Quaternions
* A quaternion is a 4-element vector that can describe a 3D rotation. Functions dealing with quaternions begin with "quat". Functions that generate quaternions include: {@link MathUtil.quatIdentity}, which generates a quaternion describing an
* absence of rotations; {@link MathUtil.quatFromVectors}, which generates a quaternion describing
* a rotation from one vector to another; {@link MathUtil.quatFromMat4}, which generates a quaternion from a [**4 × 4 matrix**](#Matrices); {@link MathUtil.quatFromAxisAngle}, which generates a quaternion from an angle and [**axis of rotation**](#Axis_of_Rotation); {@link MathUtil.quatFromTaitBryan}, which generates a quaternion from Tait-Bryan angles.
* <a id=Using_Quaternions></a>
* #### Using Quaternions
* For best results when using quaternions:
* - Store the rotation of each object as a single quaternion.
* - As rotations occur each frame, convert the rotation (which may be
* in pitch/yaw/roll or another form, depending on the input device) to a quaternion
* (see [**"Generating Quaternions"**](#Generating_Quaternions)
* and [multiply]{@link MathUtil.quatMultiply} that quaternion by the current
* quaternion to get the object's new rotation.
* - Normalize the rotation quaternion (using [`quatNormalize()`]{@link MathUtil.quatNormalize}
* or [`quatNormalizeInPlace()`]{@link MathUtil.quatNormalizeInPlace})
* every few frames. (Quaternions that describe a 3D rotation should be [**unit vectors**](#Unit_Vectors).)
* <a id=Multiplying_Quaternions></a>
* #### Multiplying Quaternions
* When two quaternions are multiplied (for example, with {@MathUtil.quatMultiply}),
* the result is a combined rotation in which the second rotation happens
* before the first rotation (when applied in the global coordinate frame).
* Like matrix multiplication, the order in which you multiply quaternions is important.
* <a id=Tait_Bryan_angles></a>
* ### Tait-Bryan angles
* Pitch-yaw-roll angles (also called Tait-Bryan angles) describe three different rotations
* of the same vector around three different axes, called the pitch, yaw, and roll axes
* (or the X, Y, z-axes, respectively), which occur one after the other. However:
* There are multiple conventions for pitch-yaw-roll angles, including the order of
* rotations (for example: pitch-roll-yaw, roll-pitch-yaw), and whether the rotations occur
* around the object's original axes ("extrinsic") or its new axes ("intrinsic").
* Rotations are multiplied like in quaternions and matrices, so the order the rotations
* occur is important. For example, a 30-degree pitch followed by a 20-degree
* roll is not the same as a 20-degree pitch followed by a 30-degree roll.
* Pitch-yaw-roll angles can cause a problem called "gimbal lock", in which a rotation along
* one axis (say, a pitch) can cause a vector to be parallel to another axis (say, the roll
* axis), so that a rotation along that axis will do nothing.
* Related functions:
* [MathUtil.quatFromTaitBryan()]{@link MathUtil.quatFromTaitBryan} -
* Converts from Tait-Bryan angles to a quaternion
* <a id=4 × 4_Matrices></a>
* ### 4 × 4 Matrices
* A 4 × 4 matrix can describe a 3D vector rotation; see [**"Rotation", earlier**](#Rotation).
* <a id=Planes></a>
* ## Planes
* A 4-element array can describe a plane in the following manner:
* The 4 elements, labeled A, B, C, and D in that order, describe a plane
* whose points satisfy the equation—
* Ax + By + Cz + D = 0
* where x, y, and z are the
* coordinates of any point lying on the plane.
* A, B, and C are
* the X, Y, and Z components of the plane's normal vector.
* D is the signed distance from the plane to the origin (0,0,0).
* It's positive if the plane's normal points toward the origin, and
* negative if it points away from the origin.
* D is the negative dot product of the
* plane's normal and any point on the plane.
* There is one method that deals with planes:
* {@link MathUtil.planeNormalizeInPlace} - Converts the plane to a form in which
* its normal has a length of 1.
* <a id=Boxes></a>
* ## Boxes
* An array of six numbers can describe an axis-aligned bounding box (AABB).
* If it does, the first three numbers are the box's minimum x-, y-, and z-coordinates,
* and the last three numbers are the box's maximum x-, y-, and z-coordinates.
* If a minimum coordinate is greater than a maximum coordinate, then the
* box is considered empty.
* Methods that deal with boxes include:
* {@link MathUtil.boxCenter} - Finds a box's center.
* {@link MathUtil.boxDimensions} - Finds a box's dimensions.
* {@link MathUtil.boxIsEmpty} - Determines whether a box is empty.
* <a id=Coordinate_Systems></a>
* ## Coordinate Systems
* There are two conventions of 3D coordinate systems, left-handed and
* right-handed:
* In a _left-handed_ coordinate system, the positive z-axis points _forward from the "eye"_ whenever the positive x-axis points to the right and the positive y-axis points up.
* In a _right-handed_ coordinate system, the positive z-axis points _backward from the "eye"_ whenever the positive x-axis points to the right and the positive y-axis points up.
* To show this more visually, point one hand's thumb to your right and
* its index finger up, and bend the other three fingers halfway down. In a
* coordinate system named after that hand (left-handed or
* right-handed), if the positive x-axis points in the thumb's
* direction and the positive y-axis points in the index finger's direction, the z-axis will
* point in the direction the other three fingers point.
* As used here, the z-axis is the [cross product]{@link MathUtil.vec3cross}
* of two perpendicular axes, namely the x-axis and the y-axis, in that order.
* Which of the X, Y, or z-axes is the right, up, or forward axis is
* arbitrary; for example, some conventions may have the z-axis, rather than Y,
* be the up axis. Therefore, these three axes are defined here to avoid
* confusion.
* <a id=Differences_in_Behavior></a>
* ### Differences in Behavior
* <a id=Projection_and_view_matrices></a>
* #### Projection and view matrices
* The difference between a left-handed and right-handed coordinate system
* affects how 3D points are transformed, mainly in the projection and view
* matrices. The projection and view matrices returned by {@link Math}
* matrix methods are designed for a right-handed coordinate system. Their
* documentation describes how to adjust them for a left-handed coordinate system.
* <a id=Rotation_angles_such_as_used_in_mat4rotate_and_quatRotate></a>
* #### Rotation angles (such as used in `mat4rotate` and `quatRotate`)
* While the [**axis of rotation**](#Axis_of_Rotation) points backward from the "eye", if the angle's value
* is positive and the [**coordinate system**](#Coordinate_Systems) is...
* ...right handed, then the angle runs counterclockwise.
* ...left handed, then the angle runs clockwise.
* While the axis of rotation points backward from the "eye", if the angle's value
* is negative, then the angle runs in the opposite direction.
* <a id=Cross_product_vec3cross_and_normals></a>
* #### Cross product (`vec3cross`) and normals
* Given a triangle formed by...
* - points (A minus C), (B minus C), and C, in that order, or
* - points A, B, and (0, 0, 0), in that order,
* the [cross product]{@link MathUtil.vec3cross} of the first point with the second,
* in that order, is a _normal_ of that triangle (a vector that's perpendicular to the triangle's surface).
* While this particular normal points backward from the "eye", the triangle's vertices
* run in a counterclockwise path for right-handed coordinate systems, or a clockwise path
* for left-handed systems. (In general, there are two possible choices for normals, which each
* point in opposite directions.)
* <a id=Winding_and_face_classification></a>
* ### Winding and face classification
* A two-dimensional triangle has counterclockwise _winding_ if its vertices are ordered in a counterclockwise path from the first to second to third to first vertex. Otherwise, it has clockwise winding. If the triangle is in 3D space, it's first transformed into 2D _window coordinates_ before its winding is found. (Window coordinates roughly correspond to screen pixels.)
* By default, in the WebGL pipeline, triangles with counterclockwise winding are _front faces_, and
* other triangles are _back faces_.
* <a id=Finding_a_triangle_s_winding></a>
* #### Finding a triangle's winding
* To find a triangle's winding, do the following calculation (X1, X2, X3 and Y1, Y2, Y3 are the window coordinates of its vertices). Note that half of the result will be the triangle's signed area.
* (X3 - X1) * (Y3 - Y2) - (X3 - X2) * (Y3 - Y1)
* If the result is positive, and the window space x-axis points right and the positive y-axis points...
* ...up (which is the case in WebGL), then the triangle
* has counterclockwise winding.
* ...down, then the triangle has clockwise winding.
* If the result is negative, then the triangle has the opposite winding.
* @class
*/
const MathUtil = {
/** @ignore */
"_frustumPoints":function(frustum) {
const p0 = frustum[0];
const p1 = frustum[1];
const p2 = frustum[2];
const p3 = frustum[3];
const p4 = frustum[4];
const p5 = frustum[5];
// left-top-near, left-bottom-near, right-top-near, ..., right-bottom-far
const ret = [];
const t1 = p2[1] * p4[2];
const t2 = p2[2] * p4[1];
const t3 = t1 - t2;
const t4 = p2[2] * p4[0];
const t5 = p2[0] * p4[2];
const t6 = t4 - t5;
const t7 = p2[0] * p4[1];
const t8 = p2[1] * p4[0];
const t9 = t7 - t8;
const t10 = p0[2] * p2[0];
const t11 = p0[0] * p2[2];
const t12 = p0[0] * p2[1];
const t13 = p0[1] * p2[0];
const t14 = p4[2] * p0[0];
const t15 = p4[0] * p0[2];
const t16 = p4[0] * p0[1];
const t17 = p4[1] * p0[0];
const t18 = 1.0 / (p0[0] * t3 + p0[1] * t6 + p0[2] * t9);
const t19 = p4[1] * p0[2];
const t20 = p4[2] * p0[1];
const t21 = p0[1] * p2[2];
const t22 = p0[2] * p2[1];
const t23 = -p0[3];
const t24 = -p2[3];
const t25 = -p4[3];
ret[0] = (t3 * t23 + (t19 - t20) * t24 + (t21 - t22) * t25) * t18;
ret[1] = (t6 * t23 + (t14 - t15) * t24 + (t10 - t11) * t25) * t18;
ret[2] = (t9 * t23 + (t16 - t17) * t24 + (t12 - t13) * t25) * t18;
const t26 = p3[1] * p4[2];
const t27 = p3[2] * p4[1];
const t28 = t26 - t27;
const t29 = p3[2] * p4[0];
const t30 = p3[0] * p4[2];
const t31 = t29 - t30;
const t32 = p3[0] * p4[1];
const t33 = p3[1] * p4[0];
const t34 = t32 - t33;
const t35 = p0[2] * p3[0];
const t36 = p0[0] * p3[2];
const t37 = p0[0] * p3[1];
const t38 = p0[1] * p3[0];
const t39 = 1.0 / (p0[0] * t28 + p0[1] * t31 + p0[2] * t34);
const t40 = p0[1] * p3[2];
const t41 = p0[2] * p3[1];
const t42 = -p3[3];
ret[3] = (t28 * t23 + (t19 - t20) * t42 + (t40 - t41) * t25) * t39;
ret[4] = (t31 * t23 + (t14 - t15) * t42 + (t35 - t36) * t25) * t39;
ret[5] = (t34 * t23 + (t16 - t17) * t42 + (t37 - t38) * t25) * t39;
const t43 = t1 - t2;
const t44 = t4 - t5;
const t45 = t7 - t8;
const t46 = p1[2] * p2[0];
const t47 = p1[0] * p2[2];
const t48 = p1[0] * p2[1];
const t49 = p1[1] * p2[0];
const t50 = p4[2] * p1[0];
const t51 = p4[0] * p1[2];
const t52 = p4[0] * p1[1];
const t53 = p4[1] * p1[0];
const t54 = 1.0 / (p1[0] * t43 + p1[1] * t44 + p1[2] * t45);
const t55 = p4[1] * p1[2];
const t56 = p4[2] * p1[1];
const t57 = p1[1] * p2[2];
const t58 = p1[2] * p2[1];
const t59 = -p1[3];
ret[6] = (t43 * t59 + (t55 - t56) * t24 + (t57 - t58) * t25) * t54;
ret[7] = (t44 * t59 + (t50 - t51) * t24 + (t46 - t47) * t25) * t54;
ret[8] = (t45 * t59 + (t52 - t53) * t24 + (t48 - t49) * t25) * t54;
const t60 = t26 - t27;
const t61 = t29 - t30;
const t62 = t32 - t33;
const t63 = p1[2] * p3[0];
const t64 = p1[0] * p3[2];
const t65 = p1[0] * p3[1];
const t66 = p1[1] * p3[0];
const t67 = 1.0 / (p1[0] * t60 + p1[1] * t61 + p1[2] * t62);
const t68 = p1[1] * p3[2];
const t69 = p1[2] * p3[1];
ret[9] = (t60 * t59 + (t55 - t56) * t42 + (t68 - t69) * t25) * t67;
ret[10] = (t61 * t59 + (t50 - t51) * t42 + (t63 - t64) * t25) * t67;
ret[11] = (t62 * t59 + (t52 - t53) * t42 + (t65 - t66) * t25) * t67;
const t70 = p2[1] * p5[2];
const t71 = p2[2] * p5[1];
const t72 = t70 - t71;
const t73 = p2[2] * p5[0];
const t74 = p2[0] * p5[2];
const t75 = t73 - t74;
const t76 = p2[0] * p5[1];
const t77 = p2[1] * p5[0];
const t78 = t76 - t77;
const t79 = p5[2] * p0[0];
const t80 = p5[0] * p0[2];
const t81 = p5[0] * p0[1];
const t82 = p5[1] * p0[0];
const t83 = 1.0 / (p0[0] * t72 + p0[1] * t75 + p0[2] * t78);
const t84 = p5[1] * p0[2];
const t85 = p5[2] * p0[1];
const t86 = -p5[3];
ret[12] = (t72 * t23 + (t84 - t85) * t24 + (t21 - t22) * t86) * t83;
ret[13] = (t75 * t23 + (t79 - t80) * t24 + (t10 - t11) * t86) * t83;
ret[14] = (t78 * t23 + (t81 - t82) * t24 + (t12 - t13) * t86) * t83;
const t87 = p3[1] * p5[2];
const t88 = p3[2] * p5[1];
const t89 = t87 - t88;
const t90 = p3[2] * p5[0];
const t91 = p3[0] * p5[2];
const t92 = t90 - t91;
const t93 = p3[0] * p5[1];
const t94 = p3[1] * p5[0];
const t95 = t93 - t94;
const t96 = 1.0 / (p0[0] * t89 + p0[1] * t92 + p0[2] * t95);
ret[15] = (t89 * t23 + (t84 - t85) * t42 + (t40 - t41) * t86) * t96;
ret[16] = (t92 * t23 + (t79 - t80) * t42 + (t35 - t36) * t86) * t96;
ret[17] = (t95 * t23 + (t81 - t82) * t42 + (t37 - t38) * t86) * t96;
const t97 = t70 - t71;
const t98 = t73 - t74;
const t99 = t76 - t77;
const t100 = p5[2] * p1[0];
const t101 = p5[0] * p1[2];
const t102 = p5[0] * p1[1];
const t103 = p5[1] * p1[0];
const t104 = 1.0 / (p1[0] * t97 + p1[1] * t98 + p1[2] * t99);
const t105 = p5[1] * p1[2];
const t106 = p5[2] * p1[1];
ret[18] = (t97 * t59 + (t105 - t106) * t24 + (t57 - t58) * t86) * t104;
ret[19] = (t98 * t59 + (t100 - t101) * t24 + (t46 - t47) * t86) * t104;
ret[20] = (t99 * t59 + (t102 - t103) * t24 + (t48 - t49) * t86) * t104;
const t107 = t87 - t88;
const t108 = t90 - t91;
const t109 = t93 - t94;
const t110 = 1.0 / (p1[0] * t107 + p1[1] * t108 + p1[2] * t109);
ret[21] = (t107 * t59 + (t105 - t106) * t42 + (t68 - t69) * t86) * t110;
ret[22] = (t108 * t59 + (t100 - t101) * t42 + (t63 - t64) * t86) * t110;
ret[23] = (t109 * t59 + (t102 - t103) * t42 + (t65 - t66) * t86) * t110;
return ret;
},
/**
* Finds the center of a 3D bounding box.
* @param {Array<number>} box An axis-aligned bounding
* box, which is an array of six values.
* The first three values are the smallest x-, y-, and z-coordinates,
* and the last three values are the largest x-, y-, and z-coordinates.
* @returns {Array<number>} A 3-element array containing the
* x-, y-, and z-coordinates, respectively, of the bounding box's
* center.
*/
"boxCenter":function(box) {
return [box[0] + (box[3] - box[0]) * 0.5,
box[1] + (box[4] - box[1]) * 0.5,
box[2] + (box[5] - box[2]) * 0.5];
},
/**
* Finds the dimensions of a 3D bounding box. This is done by subtracting
* the first three values of the given array with its last three values.
* @param {Array<number>} box An axis-aligned bounding
* box, which is an array of six values.
* The first three values are the smallest x-, y-, and z-coordinates,
* and the last three values are the largest x-, y-, and z-coordinates.
* @returns {Array<number>} A 3-element array containing the
* width, height, and depth of the bounding box, respectively. If
* at least one of the minimum coordinates is greater than its
* corresponding maximum coordinate, the array can contain
* negative values.
*/
"boxDimensions":function(box) {
return [box[3] - box[0], box[4] - box[1], box[5] - box[2]];
},
/**
* Determines whether a 3D bounding box is empty.
* This is determined if the minimum coordinate
* is larger than the corresponding maximum coordinate.
* @param {Array<number>} box An axis-aligned bounding
* box, which is an array of six values.
* The first three values are the smallest x-, y-, and z-coordinates,
* and the last three values are the largest x-, y-, and z-coordinates.
* @returns {boolean} <code>true</code> if at least one
* of the minimum coordinates is greater than its
* corresponding maximum coordinate; otherwise, <code>false</code>.
*/
"boxIsEmpty":function(box) {
return box[0] > box[3] || box[1] > box[4] || box[2] > box[5];
},
/**
* Converts a color from encoded sRGB to linear sRGB using the sRGB transfer function, and returns
* a new vector with the result.<p>Linear RGB is linear because of its linear relationship of light emitted
* by a surface of the given color.
* @param {Array<number>} srgb A three- or four-element vector giving
* the red, green, and blue components, in that order, of an sRGB color. The alpha component
* is either the fourth element in the case of a four-element vector, or 1.0
* in the case of a three-element vector. Each element in the vector ranges from 0 through 1.
* @returns {Array<number>} A three-element vector giving
* the red, green, and blue components, in that order, of the given color
* in linear sRGB. The alpha component will be as specified
* in the "srgb" parameter.
*/
"colorToLinear":function(srgb) {
return [
srgb[0] <= 0.04045 ? srgb[0] / 12.92 : Math.pow((0.055 + srgb[0]) / 1.055, 2.4),
srgb[1] <= 0.04045 ? srgb[1] / 12.92 : Math.pow((0.055 + srgb[1]) / 1.055, 2.4),
srgb[2] <= 0.04045 ? srgb[2] / 12.92 : Math.pow((0.055 + srgb[2]) / 1.055, 2.4),
srgb.length <= 3 ? 1.0 : srgb[3]];
},
/**
* Converts a color from linear sRGB to encoded sRGB using the sRGB transfer function, and returns
* a new vector with the result.<p>Linear RGB is linear because of its linear relationship of light emitted
* by a surface of the given color.
* @param {Array<number>} lin A three- or four-element vector giving
* the red, green, and blue components, in that order, of a linear RGB color. The alpha component
* is either the fourth element in the case of a four-element vector, or 1.0
* in the case of a three-element vector. Each element in the vector ranges from 0 through 1.
* @returns {Array<number>} lin A four-element vector giving
* the red, green, blue, and alpha components, in that order, of the given color
* in encoded sRGB. The alpha component will be as specified
* in the "lin" parameter.
*/
"colorTosRGB":function(lin) {
return [
lin[0] <= 0.0031308 ? 12.92 * lin[0] : Math.pow(lin[0], 1.0 / 2.4) * 1.055 - 0.055,
lin[1] <= 0.0031308 ? 12.92 * lin[1] : Math.pow(lin[1], 1.0 / 2.4) * 1.055 - 0.055,
lin[2] <= 0.0031308 ? 12.92 * lin[2] : Math.pow(lin[2], 1.0 / 2.4) * 1.055 - 0.055,
lin.length <= 3 ? 1.0 : lin[3]];
},
/**
* Determines whether an axis-aligned bounding box
* is at least partially inside a view frustum.
* @param {Array<Array<number>>} frustum An array of six
* 4-element arrays representing the six clipping planes of the
* view frustum. In order, they are the left, right, top,
* bottom, near, and far clipping planes.
* @param {Array<number>} box An axis-aligned bounding
* box in world space, which is an array of six values.
* The first three values are the smallest x-, y-, and z-coordinates,
* and the last three values are the largest x-, y-, and z-coordinates.
* @returns {boolean} <code>true</code> if the box
* may be partially or totally
* inside the frustum; <code>false</code> if the box is
* definitely outside the frustum, or if the box is empty
* (see "boxIsEmpty").
*/
"frustumHasBox":function(frustum, box) {
if(MathUtil.boxIsEmpty(box)) {
return false;
}
let i;
for (i = 0; i < 6; i++) {
const plane = frustum[i];
const p3 = plane[3];
const p0b0 = plane[0] * box[0];
const p2b2 = plane[2] * box[2];
const p1b1 = plane[1] * box[1];
if( p0b0 + p1b1 + p2b2 + p3 <= 0.0 &&
plane[0] * box[3] + plane[1] * box[4] + plane[2] * box[5] + p3 <= 0.0 &&
p0b0 + plane[1] * box[4] + p2b2 + p3 <= 0.0 &&
p0b0 + plane[1] * box[4] + plane[2] * box[5] + p3 <= 0.0 &&
p0b0 + p1b1 + plane[2] * box[5] + p3 <= 0.0 &&
plane[0] * box[3] + plane[1] * box[4] + p2b2 + p3 <= 0.0 &&
plane[0] * box[3] + p1b1 + p2b2 + p3 <= 0.0 &&
plane[0] * box[3] + p1b1 + plane[2] * box[5] + p3 <= 0.0) {
return false;
}
}
// To increase robustness in frustum culling; see
// <http://www.iquilezles.org/www/articles/frustumcorrect/frustumcorrect.htm>
const pts = MathUtil._frustumPoints(frustum);
for (i = 0; i < 3; i++) {
const minval = box[i];
if(pts[i] < minval && pts[3 + i] < minval && pts[6 + i] < minval &&
pts[9 + i] < minval && pts[12 + i] < minval && pts[15 + i] < minval &&
pts[18 + i] < minval && pts[21 + i] < minval) {
return false;
}
const maxval = box[i + 3];
if(pts[i] > maxval && pts[3 + i] > maxval && pts[6 + i] > maxval &&
pts[9 + i] > maxval && pts[12 + i] > maxval && pts[15 + i] > maxval &&
pts[18 + i] > maxval && pts[21 + i] > maxval) {
return false;
}
}
return true;
},
/**
* Determines whether a point is
* outside or inside a view frustum.
* @param {Array<Array<number>>} frustum An array of six
* 4-element arrays representing the six clipping planes of the
* view frustum. In order, they are the left, right, top,
* bottom, near, and far clipping planes.
* @param {number} x The x-coordinate of a point
* in world space.
* @param {number} y The y-coordinate of a point
* in world space.
* @param {number} z The z-coordinate of a point
* in world space.
* @returns {boolean} true if the point is inside;
* otherwise false;
*/
"frustumHasPoint":function(frustum, x, y, z) {
let i;
for (i = 0; i < 6; i++) {
const d = frustum[i][0] * x + frustum[i][1] * y +
frustum[i][2] * z + frustum[i][3];
if(d <= 0)return false;
}
return true;
},
/**
* Determines whether a sphere is at least
* partially inside a view frustum.
* @param {Array<Array<number>>} frustum An array of six
* 4-element arrays representing the six clipping planes of the
* view frustum. In order, they are the left, right, top,
* bottom, near, and far clipping planes.
* @param {number} x The x-coordinate of the sphere's center
* in world space.