littlejsengine 1.19.3 → 1.21.0
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/FAQ.md +841 -820
- package/README.md +29 -25
- package/dist/littlejs.d.ts +2857 -955
- package/dist/littlejs.esm.js +33428 -20995
- package/dist/littlejs.esm.min.js +4 -3
- package/dist/littlejs.js +33386 -20996
- package/dist/littlejs.min.js +2 -2
- package/dist/littlejs.release.js +27841 -20422
- package/package.json +10 -5
- package/plugins/audioEffects.js +28 -24
- package/plugins/box2d.js +2516 -2073
- package/plugins/drawUtilities.js +206 -31
- package/plugins/gltf.js +786 -0
- package/plugins/jsconfig.json +19 -0
- package/plugins/lightSystem.js +719 -332
- package/plugins/math3d.js +148 -27
- package/plugins/medalSystem.js +326 -280
- package/plugins/newgrounds.js +400 -199
- package/plugins/pathFinder.js +208 -175
- package/plugins/pluginExport.js +25 -0
- package/plugins/postProcess.js +96 -24
- package/plugins/render3d.js +2067 -1632
- package/plugins/render3dDebug.js +110 -0
- package/plugins/render3dEditor.js +1812 -0
- package/plugins/render3dExtras.js +1948 -0
- package/plugins/render3dLevel.js +189 -0
- package/plugins/render3dVoxels.js +514 -0
- package/plugins/sceneSystem.js +58 -0
- package/plugins/textureSheet.js +496 -458
- package/plugins/threejs.js +183 -163
- package/plugins/tweakables.js +411 -0
- package/plugins/tweenSystem.js +265 -145
- package/plugins/uiSystem.js +2024 -1687
- package/plugins/zzfxm.js +159 -159
- package/src/engine.js +378 -97
- package/src/engineAudio.js +231 -127
- package/src/engineBuild.mjs +292 -256
- package/src/engineDebug.js +967 -743
- package/src/engineDraw.js +391 -198
- package/src/engineEditor.js +2452 -0
- package/src/engineExport.js +18 -0
- package/src/engineInput.js +1466 -1293
- package/src/engineLogo.js +19 -0
- package/src/engineMath.js +1274 -1252
- package/src/engineObject.js +197 -82
- package/src/engineParticles.js +583 -532
- package/src/engineRelease.js +79 -45
- package/src/engineSettings.js +115 -29
- package/src/engineTileLayer.js +995 -741
- package/src/engineUtilities.js +19 -13
- package/src/engineWebGL.js +239 -82
- package/src/jsconfig.json +17 -13
- package/plugins/box2d.wasm.js +0 -630
- package/plugins/box2d.wasm.wasm +0 -0
package/plugins/math3d.js
CHANGED
|
@@ -288,6 +288,7 @@ class Vector3
|
|
|
288
288
|
|
|
289
289
|
// scratch for multiply, nothing keeps a reference to it
|
|
290
290
|
const matrix4Scratch = new Float32Array(16);
|
|
291
|
+
const matrix4Identity = new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
|
|
291
292
|
|
|
292
293
|
/**
|
|
293
294
|
* 4x4 transform matrix for moving, rotating and scaling points in 3D
|
|
@@ -330,22 +331,23 @@ class Matrix4
|
|
|
330
331
|
return r;
|
|
331
332
|
}
|
|
332
333
|
|
|
333
|
-
/** Returns a
|
|
334
|
+
/** Returns a rotation matrix, rolled first, then pitched, then yawed
|
|
334
335
|
* @param {Vector3} euler - vec3(pitch, yaw, roll) in radians
|
|
336
|
+
* @param {Matrix4} [matrix] - Written into instead of a new one, for a loop that builds many
|
|
335
337
|
* @return {Matrix4} */
|
|
336
|
-
static rotation(euler)
|
|
338
|
+
static rotation(euler, matrix=new Matrix4)
|
|
337
339
|
{
|
|
338
340
|
ASSERT_VECTOR3_VALID(euler);
|
|
339
341
|
const cx = cos(euler.x), sx = sin(euler.x);
|
|
340
342
|
const cy = cos(euler.y), sy = sin(euler.y);
|
|
341
343
|
const cz = cos(euler.z), sz = sin(euler.z);
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
m[
|
|
346
|
-
m[
|
|
347
|
-
m[
|
|
348
|
-
return
|
|
344
|
+
const m = matrix.m;
|
|
345
|
+
// R = Ry * Rx * Rz written out, column major, every element set so a reused matrix comes out clean
|
|
346
|
+
m[0] = cy*cz + sy*sx*sz; m[1] = cx*sz; m[2] = -sy*cz + cy*sx*sz; m[3] = 0;
|
|
347
|
+
m[4] = -cy*sz + sy*sx*cz; m[5] = cx*cz; m[6] = sy*sz + cy*sx*cz; m[7] = 0;
|
|
348
|
+
m[8] = sy*cx; m[9] = -sx; m[10] = cy*cx; m[11] = 0;
|
|
349
|
+
m[12] = m[13] = m[14] = 0; m[15] = 1;
|
|
350
|
+
return matrix;
|
|
349
351
|
}
|
|
350
352
|
|
|
351
353
|
/** Returns a new scale matrix
|
|
@@ -416,8 +418,10 @@ class Matrix4
|
|
|
416
418
|
if (!z.lengthSquared())
|
|
417
419
|
z = vec3(0, 0, 1); // eye is on the target, face -Z
|
|
418
420
|
let x = up.cross(z).normalize();
|
|
419
|
-
|
|
420
|
-
|
|
421
|
+
// up is along the view direction, pick another; looking straight down or up keeps +X as the right axis,
|
|
422
|
+
// as three.js does and as a view tilting there from the +Z side ends up
|
|
423
|
+
if (!x.lengthSquared())
|
|
424
|
+
x = (abs(z.y) > .99 ? vec3(0, 0, z.y > 0 ? -1 : 1) : vec3(0, 1, 0)).cross(z).normalize();
|
|
421
425
|
const y = z.cross(x);
|
|
422
426
|
return new Matrix4([x.x, x.y, x.z, 0, y.x, y.y, y.z, 0, z.x, z.y, z.z, 0, eye.x, eye.y, eye.z, 1]);
|
|
423
427
|
}
|
|
@@ -530,6 +534,41 @@ class Matrix4
|
|
|
530
534
|
* @return {Vector3} */
|
|
531
535
|
getTranslation() { return new Vector3(this.m[12], this.m[13], this.m[14]); }
|
|
532
536
|
|
|
537
|
+
/** Returns the determinant of the rotation and scale part: negative when the matrix mirrors, 0 when it flattens a
|
|
538
|
+
* shape and has no inverse
|
|
539
|
+
* @return {number} */
|
|
540
|
+
determinant()
|
|
541
|
+
{
|
|
542
|
+
const m = this.m;
|
|
543
|
+
return m[0]*(m[5]*m[10] - m[6]*m[9]) - m[4]*(m[1]*m[10] - m[2]*m[9]) + m[8]*(m[1]*m[6] - m[2]*m[5]);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/** Returns the scale part of this matrix, the length of each axis; a mirroring matrix shows as a negative x
|
|
547
|
+
* @return {Vector3} */
|
|
548
|
+
getScale()
|
|
549
|
+
{
|
|
550
|
+
const m = this.m;
|
|
551
|
+
const x = hypot(m[0], m[1], m[2]), y = hypot(m[4], m[5], m[6]), z = hypot(m[8], m[9], m[10]);
|
|
552
|
+
return new Vector3(this.determinant() < 0 ? -x : x, y, z);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** Returns the rotation part of this matrix as vec3(pitch, yaw, roll), the angles Matrix4.rotation builds it from
|
|
556
|
+
* - The scale is divided out first, so it works on a full transform
|
|
557
|
+
* - A matrix with shear, from a scaled parent with a turned child, has no exact answer and gets the nearest
|
|
558
|
+
* @return {Vector3} */
|
|
559
|
+
getRotation()
|
|
560
|
+
{
|
|
561
|
+
// the axes at unit length, see Matrix4.rotation for which element is which
|
|
562
|
+
const m = this.m, s = this.getScale();
|
|
563
|
+
const sx = s.x || 1, sy = s.y || 1, sz = s.z || 1;
|
|
564
|
+
const m1 = m[1] / sx, m5 = m[5] / sy, m8 = m[8] / sz, m9 = m[9] / sz, m10 = m[10] / sz;
|
|
565
|
+
const pitch = Math.asin(clamp(-m9, -1, 1));
|
|
566
|
+
if (abs(m9) < 1 - 1e-6)
|
|
567
|
+
return new Vector3(pitch, atan2(m8, m10), atan2(m1, m5));
|
|
568
|
+
// straight up or down: yaw and roll turn about the same axis, so the roll is zero and yaw takes it all
|
|
569
|
+
return new Vector3(pitch, atan2(m[4] / sy * -m9, m[0] / sx), 0);
|
|
570
|
+
}
|
|
571
|
+
|
|
533
572
|
/** Returns a string representation of this matrix for debugging
|
|
534
573
|
* @return {string} */
|
|
535
574
|
toString()
|
|
@@ -550,18 +589,20 @@ class Matrix4
|
|
|
550
589
|
* @param {Vector3} [pos]
|
|
551
590
|
* @param {Vector3} [rotation] - vec3(pitch, yaw, roll) in radians
|
|
552
591
|
* @param {Vector3} [scale]
|
|
592
|
+
* @param {Matrix4} [matrix] - Written into instead of a new one, for a loop that builds many
|
|
553
593
|
* @return {Matrix4}
|
|
554
594
|
* @memberof Math3D
|
|
555
595
|
*/
|
|
556
|
-
function buildMatrix(pos, rotation, scale)
|
|
596
|
+
function buildMatrix(pos, rotation, scale, matrix=new Matrix4)
|
|
557
597
|
{
|
|
558
598
|
ASSERT(!pos || isVector3(pos), 'pos must be a Vector3', pos);
|
|
559
599
|
ASSERT(!scale || isVector3(scale), 'scale must be a Vector3', scale);
|
|
600
|
+
ASSERT(matrix instanceof Matrix4, 'the matrix to write into must be a Matrix4');
|
|
560
601
|
// scale the rotation columns and drop the position in, instead of multiplying three matrices
|
|
561
602
|
// an object that is not turned at all is most of a big scene, and identity is what the six
|
|
562
603
|
// trig calls would have worked out to anyway
|
|
563
|
-
const turned = rotation && (rotation.x || rotation.y || rotation.z);
|
|
564
|
-
|
|
604
|
+
const turned = rotation && (rotation.x || rotation.y || rotation.z), m = matrix.m;
|
|
605
|
+
turned ? Matrix4.rotation(rotation, matrix) : m.set(matrix4Identity);
|
|
565
606
|
if (scale)
|
|
566
607
|
{
|
|
567
608
|
m[0] *= scale.x; m[1] *= scale.x; m[2] *= scale.x;
|
|
@@ -611,36 +652,62 @@ class Ray3D
|
|
|
611
652
|
|
|
612
653
|
///////////////////////////////////////////////////////////////////////////////
|
|
613
654
|
// 3D collision helpers, none of them change anything that is passed in
|
|
614
|
-
// Boxes sit centered on pos and take a full size, like drawRect
|
|
655
|
+
// Boxes sit centered on pos and take a full size, like drawRect, upright unless given a rotation, an Euler vec3 like
|
|
656
|
+
// rotation3D, which turns them about their center
|
|
615
657
|
// Cylinders stand up the Y axis, centered on pos, with a full height
|
|
616
658
|
// Names that could be mistaken for 2D functions get a 3D suffix
|
|
617
659
|
|
|
660
|
+
// whether a rotation turns anything, a missing one does not
|
|
661
|
+
const isTurned3D = (rotation)=> !!rotation && !!(rotation.x || rotation.y || rotation.z);
|
|
662
|
+
|
|
663
|
+
// a turned box's three unit axes, the columns of its rotation
|
|
664
|
+
function boxAxes3D(rotation)
|
|
665
|
+
{
|
|
666
|
+
const m = buildMatrix(undefined, rotation).m;
|
|
667
|
+
return [vec3(m[0], m[1], m[2]), vec3(m[4], m[5], m[6]), vec3(m[8], m[9], m[10])];
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// a point in a turned box's own space, from its center, and a vector from that space back to the world's
|
|
671
|
+
function boxLocal3D(point, pos, axes)
|
|
672
|
+
{
|
|
673
|
+
const d = point.subtract(pos);
|
|
674
|
+
return vec3(d.dot(axes[0]), d.dot(axes[1]), d.dot(axes[2]));
|
|
675
|
+
}
|
|
676
|
+
const boxWorld3D = (v, axes)=> axes[0].scale(v.x).add(axes[1].scale(v.y)).add(axes[2].scale(v.z));
|
|
677
|
+
|
|
618
678
|
/**
|
|
619
|
-
* Check if a point is inside
|
|
679
|
+
* Check if a point is inside a box, boundary is inclusive
|
|
620
680
|
* @param {Vector3} point
|
|
621
681
|
* @param {Vector3} pos - Center of the box
|
|
622
682
|
* @param {Vector3} size - Full size of the box
|
|
683
|
+
* @param {Vector3} [rotation] - How the box is turned, upright when left out
|
|
623
684
|
* @return {boolean}
|
|
624
685
|
* @memberof Math3D
|
|
625
686
|
*/
|
|
626
|
-
function isPointInBox3D(point, pos, size)
|
|
687
|
+
function isPointInBox3D(point, pos, size, rotation)
|
|
627
688
|
{
|
|
689
|
+
if (isTurned3D(rotation))
|
|
690
|
+
return isPointInBox3D(boxLocal3D(point, pos, boxAxes3D(rotation)), vec3(), size);
|
|
628
691
|
return abs(point.x - pos.x) <= size.x/2 &&
|
|
629
692
|
abs(point.y - pos.y) <= size.y/2 &&
|
|
630
693
|
abs(point.z - pos.z) <= size.z/2;
|
|
631
694
|
}
|
|
632
695
|
|
|
633
696
|
/**
|
|
634
|
-
* Check if two
|
|
697
|
+
* Check if two boxes are overlapping, touching edges do not overlap
|
|
635
698
|
* @param {Vector3} posA
|
|
636
699
|
* @param {Vector3} sizeA - Full size of box A
|
|
637
700
|
* @param {Vector3} posB
|
|
638
701
|
* @param {Vector3} [sizeB] - Full size of box B, zero for a point
|
|
702
|
+
* @param {Vector3} [rotationA] - How box A is turned, upright when left out
|
|
703
|
+
* @param {Vector3} [rotationB] - How box B is turned
|
|
639
704
|
* @return {boolean}
|
|
640
705
|
* @memberof Math3D
|
|
641
706
|
*/
|
|
642
|
-
function isOverlapping3D(posA, sizeA, posB, sizeB=vec3())
|
|
707
|
+
function isOverlapping3D(posA, sizeA, posB, sizeB=vec3(), rotationA, rotationB)
|
|
643
708
|
{
|
|
709
|
+
if (isTurned3D(rotationA) || isTurned3D(rotationB))
|
|
710
|
+
return !!collideBoxBox3D(posA, sizeA, posB, sizeB, rotationA, rotationB);
|
|
644
711
|
const d = posA.subtract(posB);
|
|
645
712
|
return abs(d.x) < (sizeA.x + sizeB.x)/2 &&
|
|
646
713
|
abs(d.y) < (sizeA.y + sizeB.y)/2 &&
|
|
@@ -669,16 +736,19 @@ function collideSphereSphere(posA, radiusA, posB, radiusB)
|
|
|
669
736
|
}
|
|
670
737
|
|
|
671
738
|
/**
|
|
672
|
-
* Returns the vector to move a sphere out of
|
|
739
|
+
* Returns the vector to move a sphere out of a box, or undefined
|
|
673
740
|
* @param {Vector3} pos - Sphere center
|
|
674
741
|
* @param {number} radius
|
|
675
742
|
* @param {Vector3} boxPos
|
|
676
743
|
* @param {Vector3} boxSize - Full size of the box
|
|
744
|
+
* @param {Vector3} [boxRotation] - How the box is turned, upright when left out
|
|
677
745
|
* @return {Vector3|undefined}
|
|
678
746
|
* @memberof Math3D
|
|
679
747
|
*/
|
|
680
|
-
function collideSphereBox(pos, radius, boxPos, boxSize)
|
|
748
|
+
function collideSphereBox(pos, radius, boxPos, boxSize, boxRotation)
|
|
681
749
|
{
|
|
750
|
+
if (isTurned3D(boxRotation))
|
|
751
|
+
return collideSphereOrientedBox3D(pos, radius, boxPos, boxSize, boxAxes3D(boxRotation));
|
|
682
752
|
const h = boxSize.scale(.5);
|
|
683
753
|
const closest = vec3(
|
|
684
754
|
clamp(pos.x, boxPos.x - h.x, boxPos.x + h.x),
|
|
@@ -766,15 +836,20 @@ function collideSphereCylinder(pos, radius, cylinderPos, cylinderRadius, cylinde
|
|
|
766
836
|
/**
|
|
767
837
|
* Returns the vector to move box A by so it no longer overlaps box B, the shortest way out, or undefined
|
|
768
838
|
* - The 3D twin of collideBoxBox
|
|
839
|
+
* - Turned boxes are tested by the separating axis test, the push is along the direction they overlap least on
|
|
769
840
|
* @param {Vector3} posA
|
|
770
841
|
* @param {Vector3} sizeA - Full size of box A
|
|
771
842
|
* @param {Vector3} posB
|
|
772
843
|
* @param {Vector3} sizeB - Full size of box B
|
|
844
|
+
* @param {Vector3} [rotationA] - How box A is turned, upright when left out
|
|
845
|
+
* @param {Vector3} [rotationB] - How box B is turned
|
|
773
846
|
* @return {Vector3|undefined}
|
|
774
847
|
* @memberof Math3D
|
|
775
848
|
*/
|
|
776
|
-
function collideBoxBox3D(posA, sizeA, posB, sizeB)
|
|
849
|
+
function collideBoxBox3D(posA, sizeA, posB, sizeB, rotationA, rotationB)
|
|
777
850
|
{
|
|
851
|
+
if (isTurned3D(rotationA) || isTurned3D(rotationB))
|
|
852
|
+
return collideOrientedBoxes3D(posA, sizeA, boxAxes3D(rotationA), posB, sizeB, boxAxes3D(rotationB));
|
|
778
853
|
const d = posA.subtract(posB);
|
|
779
854
|
const overlapX = (sizeA.x + sizeB.x)/2 - abs(d.x);
|
|
780
855
|
const overlapY = (sizeA.y + sizeB.y)/2 - abs(d.y);
|
|
@@ -784,6 +859,44 @@ function collideBoxBox3D(posA, sizeA, posB, sizeB)
|
|
|
784
859
|
return pushOutAxis3D(d, overlapX, overlapY, overlapZ);
|
|
785
860
|
}
|
|
786
861
|
|
|
862
|
+
// the push to move a sphere out of a box turned to these axes: in the box's own space it is upright, and the push
|
|
863
|
+
// goes back out turned
|
|
864
|
+
function collideSphereOrientedBox3D(pos, radius, boxPos, boxSize, axes)
|
|
865
|
+
{
|
|
866
|
+
const push = collideSphereBox(boxLocal3D(pos, boxPos, axes), radius, vec3(), boxSize);
|
|
867
|
+
return push && boxWorld3D(push, axes);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// the world's axes, for an upright box among turned ones
|
|
871
|
+
const BOX_WORLD_AXES = Object.freeze([vec3(1, 0, 0), vec3(0, 1, 0), vec3(0, 0, 1)]);
|
|
872
|
+
|
|
873
|
+
// the shortest push to move box A out of box B by the separating axis test: each box's three face directions and
|
|
874
|
+
// the nine across an edge of each; a gap on any of them is no touch, and the push is along the least overlap, from
|
|
875
|
+
// B to A; an edge direction has to overlap clearly less to win, so a box lying on another leaves by the face
|
|
876
|
+
function collideOrientedBoxes3D(posA, sizeA, axesA, posB, sizeB, axesB)
|
|
877
|
+
{
|
|
878
|
+
const d = posA.subtract(posB), ha = sizeA.scale(.5), hb = sizeB.scale(.5);
|
|
879
|
+
const reach = (h, axes, n)=> h.x * abs(axes[0].dot(n)) + h.y * abs(axes[1].dot(n)) + h.z * abs(axes[2].dot(n));
|
|
880
|
+
let push, least = Infinity;
|
|
881
|
+
const separated = (axis, weight)=>
|
|
882
|
+
{
|
|
883
|
+
const lengthSquared = axis.lengthSquared();
|
|
884
|
+
if (lengthSquared < 1e-12) return false; // parallel edges give no direction to test
|
|
885
|
+
const n = axis.scale(lengthSquared ** -.5), along = d.dot(n);
|
|
886
|
+
const overlap = reach(ha, axesA, n) + reach(hb, axesB, n) - abs(along);
|
|
887
|
+
if (overlap <= 0) return true;
|
|
888
|
+
if (overlap * weight < least)
|
|
889
|
+
least = overlap * weight, push = n.scale(along < 0 ? -overlap : overlap);
|
|
890
|
+
return false;
|
|
891
|
+
};
|
|
892
|
+
for (const axis of [...axesA, ...axesB])
|
|
893
|
+
if (separated(axis, 1)) return;
|
|
894
|
+
for (const a of axesA)
|
|
895
|
+
for (const b of axesB)
|
|
896
|
+
if (separated(a.cross(b), 1.05)) return;
|
|
897
|
+
return push;
|
|
898
|
+
}
|
|
899
|
+
|
|
787
900
|
/**
|
|
788
901
|
* Returns the distance along the ray to the first intersection with a sphere, or undefined
|
|
789
902
|
* - The hit is ray.getPosition(distance), a direction that is not unit length scales the distance
|
|
@@ -798,12 +911,12 @@ function raycastSphere(ray, pos, radius)
|
|
|
798
911
|
{
|
|
799
912
|
const {origin, direction} = ray;
|
|
800
913
|
const oc = origin.subtract(pos);
|
|
914
|
+
const c = oc.dot(oc) - radius*radius;
|
|
915
|
+
if (c < 0)
|
|
916
|
+
return 0; // origin is inside the sphere, even for a ray of no length, as raycastBox gives
|
|
801
917
|
const a = direction.dot(direction);
|
|
802
918
|
if (!a)
|
|
803
919
|
return undefined;
|
|
804
|
-
const c = oc.dot(oc) - radius*radius;
|
|
805
|
-
if (c < 0)
|
|
806
|
-
return 0; // origin is inside the sphere
|
|
807
920
|
const b = 2*oc.dot(direction);
|
|
808
921
|
const discriminant = b*b - 4*a*c;
|
|
809
922
|
if (discriminant < 0)
|
|
@@ -832,17 +945,25 @@ function raycastPlane(ray, planePos, planeNormal)
|
|
|
832
945
|
}
|
|
833
946
|
|
|
834
947
|
/**
|
|
835
|
-
* Returns the distance along the ray to the first intersection with
|
|
948
|
+
* Returns the distance along the ray to the first intersection with a box, or undefined
|
|
836
949
|
* - The hit is ray.getPosition(distance), a direction that is not unit length scales the distance
|
|
837
950
|
* - A ray starting inside the box is already there, so it gets back 0
|
|
838
951
|
* @param {Ray3D} ray
|
|
839
952
|
* @param {Vector3} pos - Center of the box
|
|
840
953
|
* @param {Vector3} size - Full size of the box
|
|
954
|
+
* @param {Vector3} [rotation] - How the box is turned, upright when left out
|
|
841
955
|
* @return {number|undefined}
|
|
842
956
|
* @memberof Math3D
|
|
843
957
|
*/
|
|
844
|
-
function raycastBox(ray, pos, size)
|
|
958
|
+
function raycastBox(ray, pos, size, rotation)
|
|
845
959
|
{
|
|
960
|
+
if (isTurned3D(rotation))
|
|
961
|
+
{
|
|
962
|
+
// the ray in the box's own space, where the box is upright; turning keeps the distances
|
|
963
|
+
const axes = boxAxes3D(rotation), d = ray.direction;
|
|
964
|
+
const direction = vec3(d.dot(axes[0]), d.dot(axes[1]), d.dot(axes[2]));
|
|
965
|
+
return raycastBox(new Ray3D(boxLocal3D(ray.origin, pos, axes), direction), vec3(), size);
|
|
966
|
+
}
|
|
846
967
|
const {origin, direction} = ray;
|
|
847
968
|
const h = size.scale(.5);
|
|
848
969
|
const boxMin = pos.subtract(h), boxMax = pos.add(h);
|