@aura3d/math 1.3.3 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +35 -2
- package/src/Box3.ts +0 -65
- package/src/Color.ts +0 -49
- package/src/Curves.ts +0 -79
- package/src/Easing.ts +0 -24
- package/src/Euler.ts +0 -30
- package/src/Frustum.ts +0 -43
- package/src/Interpolation.ts +0 -34
- package/src/Matrix3.ts +0 -54
- package/src/Matrix4.ts +0 -240
- package/src/Plane.ts +0 -34
- package/src/Quaternion.ts +0 -178
- package/src/Random.ts +0 -32
- package/src/Ray.ts +0 -67
- package/src/Sphere.ts +0 -18
- package/src/Transform.ts +0 -33
- package/src/Vector2.ts +0 -66
- package/src/Vector3.ts +0 -101
- package/src/Vector4.ts +0 -55
- package/src/index.ts +0 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aura3d/math",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -9,5 +9,38 @@
|
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
10
|
"import": "./dist/index.js"
|
|
11
11
|
}
|
|
12
|
-
}
|
|
12
|
+
},
|
|
13
|
+
"description": "Deterministic vectors, matrices, quaternions, colors, rays, bounds, frustums, transforms, interpolation, easing, and seeded random math for Aura3D.",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"aura3d",
|
|
16
|
+
"3d",
|
|
17
|
+
"browser-3d",
|
|
18
|
+
"web-3d",
|
|
19
|
+
"typescript",
|
|
20
|
+
"math",
|
|
21
|
+
"vectors",
|
|
22
|
+
"matrices",
|
|
23
|
+
"quaternion",
|
|
24
|
+
"geometry",
|
|
25
|
+
"bounds",
|
|
26
|
+
"random",
|
|
27
|
+
"deterministic"
|
|
28
|
+
],
|
|
29
|
+
"homepage": "https://aura3d.auraone.ai",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/auraoneai/aura3d.git",
|
|
33
|
+
"directory": "packages/math"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/auraoneai/aura3d/issues"
|
|
37
|
+
},
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"README.md",
|
|
44
|
+
"dist"
|
|
45
|
+
]
|
|
13
46
|
}
|
package/src/Box3.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { Matrix4 } from "./Matrix4.js";
|
|
2
|
-
import { Sphere } from "./Sphere.js";
|
|
3
|
-
import { Vector3 } from "./Vector3.js";
|
|
4
|
-
|
|
5
|
-
export class Box3 {
|
|
6
|
-
constructor(
|
|
7
|
-
readonly min = new Vector3(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY),
|
|
8
|
-
readonly max = new Vector3(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY)
|
|
9
|
-
) {}
|
|
10
|
-
|
|
11
|
-
static fromPoints(points: readonly Vector3[]): Box3 {
|
|
12
|
-
return points.reduce((box, point) => box.expandByPoint(point), new Box3());
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
isEmpty(): boolean {
|
|
16
|
-
return this.max.x < this.min.x || this.max.y < this.min.y || this.max.z < this.min.z;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
expandByPoint(point: Vector3): Box3 {
|
|
20
|
-
return new Box3(this.min.min(point), this.max.max(point));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
union(box: Box3): Box3 {
|
|
24
|
-
if (this.isEmpty()) return box;
|
|
25
|
-
if (box.isEmpty()) return this;
|
|
26
|
-
return new Box3(this.min.min(box.min), this.max.max(box.max));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
intersectsBox(box: Box3): boolean {
|
|
30
|
-
if (this.isEmpty() || box.isEmpty()) return false;
|
|
31
|
-
return !(box.max.x < this.min.x || box.min.x > this.max.x || box.max.y < this.min.y || box.min.y > this.max.y || box.max.z < this.min.z || box.min.z > this.max.z);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
containsPoint(point: Vector3): boolean {
|
|
35
|
-
return !this.isEmpty() && point.x >= this.min.x && point.x <= this.max.x && point.y >= this.min.y && point.y <= this.max.y && point.z >= this.min.z && point.z <= this.max.z;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
getCenter(): Vector3 {
|
|
39
|
-
return this.isEmpty() ? Vector3.zero.clone() : this.min.add(this.max).multiplyScalar(0.5);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
getSize(): Vector3 {
|
|
43
|
-
return this.isEmpty() ? Vector3.zero.clone() : this.max.subtract(this.min);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
getBoundingSphere(): Sphere {
|
|
47
|
-
const center = this.getCenter();
|
|
48
|
-
return new Sphere(center, center.distanceTo(this.max));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
transform(matrix: Matrix4): Box3 {
|
|
52
|
-
if (this.isEmpty()) return new Box3();
|
|
53
|
-
const corners = [
|
|
54
|
-
new Vector3(this.min.x, this.min.y, this.min.z),
|
|
55
|
-
new Vector3(this.min.x, this.min.y, this.max.z),
|
|
56
|
-
new Vector3(this.min.x, this.max.y, this.min.z),
|
|
57
|
-
new Vector3(this.min.x, this.max.y, this.max.z),
|
|
58
|
-
new Vector3(this.max.x, this.min.y, this.min.z),
|
|
59
|
-
new Vector3(this.max.x, this.min.y, this.max.z),
|
|
60
|
-
new Vector3(this.max.x, this.max.y, this.min.z),
|
|
61
|
-
new Vector3(this.max.x, this.max.y, this.max.z)
|
|
62
|
-
];
|
|
63
|
-
return Box3.fromPoints(corners.map((corner) => matrix.transformPoint(corner)));
|
|
64
|
-
}
|
|
65
|
-
}
|
package/src/Color.ts
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { clamp } from "./Interpolation.js";
|
|
2
|
-
|
|
3
|
-
export class Color {
|
|
4
|
-
constructor(
|
|
5
|
-
readonly r = 1,
|
|
6
|
-
readonly g = 1,
|
|
7
|
-
readonly b = 1,
|
|
8
|
-
readonly a = 1
|
|
9
|
-
) {
|
|
10
|
-
for (const channel of [r, g, b, a]) {
|
|
11
|
-
if (!Number.isFinite(channel)) throw new RangeError("Color channels must be finite.");
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
static fromSRGB(r: number, g: number, b: number, a = 1): Color {
|
|
16
|
-
return new Color(srgbToLinear(r), srgbToLinear(g), srgbToLinear(b), a);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
toSRGB(): Color {
|
|
20
|
-
return new Color(linearToSrgb(this.r), linearToSrgb(this.g), linearToSrgb(this.b), this.a);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
clamp01(): Color {
|
|
24
|
-
return new Color(clamp(this.r), clamp(this.g), clamp(this.b), clamp(this.a));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
lerp(to: Color, t: number): Color {
|
|
28
|
-
return new Color(
|
|
29
|
-
this.r + (to.r - this.r) * t,
|
|
30
|
-
this.g + (to.g - this.g) * t,
|
|
31
|
-
this.b + (to.b - this.b) * t,
|
|
32
|
-
this.a + (to.a - this.a) * t
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
equals(color: Color, epsilon = 1e-10): boolean {
|
|
37
|
-
return Math.abs(this.r - color.r) <= epsilon && Math.abs(this.g - color.g) <= epsilon && Math.abs(this.b - color.b) <= epsilon && Math.abs(this.a - color.a) <= epsilon;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function srgbToLinear(value: number): number {
|
|
42
|
-
const v = clamp(value);
|
|
43
|
-
return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function linearToSrgb(value: number): number {
|
|
47
|
-
const v = clamp(value);
|
|
48
|
-
return v <= 0.0031308 ? v * 12.92 : 1.055 * Math.pow(v, 1 / 2.4) - 0.055;
|
|
49
|
-
}
|
package/src/Curves.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { Vector3 } from "./Vector3.js";
|
|
2
|
-
|
|
3
|
-
export interface CurveSample {
|
|
4
|
-
readonly position: Vector3;
|
|
5
|
-
readonly tangent: Vector3;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export class CatmullRomCurve3 {
|
|
9
|
-
constructor(public readonly points: readonly Vector3[]) {
|
|
10
|
-
if (points.length < 2) throw new Error("CatmullRomCurve3 requires at least two points.");
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
getPoint(t: number): Vector3 {
|
|
14
|
-
const clamped = clamp01(t);
|
|
15
|
-
const scaled = clamped * (this.points.length - 1);
|
|
16
|
-
const index = Math.min(Math.floor(scaled), this.points.length - 2);
|
|
17
|
-
const localT = scaled - index;
|
|
18
|
-
const p0 = this.points[Math.max(0, index - 1)]!;
|
|
19
|
-
const p1 = this.points[index]!;
|
|
20
|
-
const p2 = this.points[index + 1]!;
|
|
21
|
-
const p3 = this.points[Math.min(this.points.length - 1, index + 2)]!;
|
|
22
|
-
return catmullRom(p0, p1, p2, p3, localT);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
getTangent(t: number): Vector3 {
|
|
26
|
-
const delta = 1e-4;
|
|
27
|
-
const before = this.getPoint(Math.max(0, t - delta));
|
|
28
|
-
const after = this.getPoint(Math.min(1, t + delta));
|
|
29
|
-
return after.subtract(before).normalize();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
sample(t: number): CurveSample {
|
|
33
|
-
return { position: this.getPoint(t), tangent: this.getTangent(t) };
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export class CubicBezierCurve3 {
|
|
38
|
-
constructor(
|
|
39
|
-
public readonly p0: Vector3,
|
|
40
|
-
public readonly p1: Vector3,
|
|
41
|
-
public readonly p2: Vector3,
|
|
42
|
-
public readonly p3: Vector3
|
|
43
|
-
) {}
|
|
44
|
-
|
|
45
|
-
getPoint(t: number): Vector3 {
|
|
46
|
-
const u = 1 - clamp01(t);
|
|
47
|
-
const tt = clamp01(t) * clamp01(t);
|
|
48
|
-
const uu = u * u;
|
|
49
|
-
const uuu = uu * u;
|
|
50
|
-
const ttt = tt * clamp01(t);
|
|
51
|
-
return this.p0.multiplyScalar(uuu)
|
|
52
|
-
.add(this.p1.multiplyScalar(3 * uu * clamp01(t)))
|
|
53
|
-
.add(this.p2.multiplyScalar(3 * u * tt))
|
|
54
|
-
.add(this.p3.multiplyScalar(ttt));
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
getTangent(t: number): Vector3 {
|
|
58
|
-
const u = 1 - clamp01(t);
|
|
59
|
-
return this.p1.subtract(this.p0).multiplyScalar(3 * u * u)
|
|
60
|
-
.add(this.p2.subtract(this.p1).multiplyScalar(6 * u * clamp01(t)))
|
|
61
|
-
.add(this.p3.subtract(this.p2).multiplyScalar(3 * clamp01(t) * clamp01(t)))
|
|
62
|
-
.normalize();
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function catmullRom(p0: Vector3, p1: Vector3, p2: Vector3, p3: Vector3, t: number): Vector3 {
|
|
67
|
-
const t2 = t * t;
|
|
68
|
-
const t3 = t2 * t;
|
|
69
|
-
return p1.multiplyScalar(2)
|
|
70
|
-
.add(p2.subtract(p0).multiplyScalar(t))
|
|
71
|
-
.add(p0.multiplyScalar(2).subtract(p1.multiplyScalar(5)).add(p2.multiplyScalar(4)).subtract(p3).multiplyScalar(t2))
|
|
72
|
-
.add(p3.subtract(p0).add(p1.multiplyScalar(3).subtract(p2.multiplyScalar(3))).multiplyScalar(t3))
|
|
73
|
-
.multiplyScalar(0.5);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function clamp01(value: number): number {
|
|
77
|
-
if (!Number.isFinite(value)) throw new Error("Curve parameter must be finite.");
|
|
78
|
-
return Math.min(1, Math.max(0, value));
|
|
79
|
-
}
|
package/src/Easing.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export const Easing = Object.freeze({
|
|
2
|
-
linear(t: number): number {
|
|
3
|
-
assertUnit(t);
|
|
4
|
-
return t;
|
|
5
|
-
},
|
|
6
|
-
easeInQuad(t: number): number {
|
|
7
|
-
assertUnit(t);
|
|
8
|
-
return t * t;
|
|
9
|
-
},
|
|
10
|
-
easeOutQuad(t: number): number {
|
|
11
|
-
assertUnit(t);
|
|
12
|
-
return t * (2 - t);
|
|
13
|
-
},
|
|
14
|
-
easeInOutCubic(t: number): number {
|
|
15
|
-
assertUnit(t);
|
|
16
|
-
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
function assertUnit(t: number): void {
|
|
21
|
-
if (!Number.isFinite(t) || t < 0 || t > 1) {
|
|
22
|
-
throw new RangeError("Easing input must be a finite value in [0, 1].");
|
|
23
|
-
}
|
|
24
|
-
}
|
package/src/Euler.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { Quaternion, type EulerOrder } from "./Quaternion.js";
|
|
2
|
-
|
|
3
|
-
export class Euler {
|
|
4
|
-
constructor(
|
|
5
|
-
readonly x = 0,
|
|
6
|
-
readonly y = 0,
|
|
7
|
-
readonly z = 0,
|
|
8
|
-
readonly order: EulerOrder = "XYZ"
|
|
9
|
-
) {
|
|
10
|
-
if (![x, y, z].every(Number.isFinite)) throw new RangeError("Euler angles must be finite.");
|
|
11
|
-
if (order !== "XYZ") throw new RangeError(`Unsupported Euler order: ${order}`);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
toQuaternion(): Quaternion {
|
|
15
|
-
return Quaternion.fromEuler(this.x, this.y, this.z, this.order);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
equals(euler: Euler, epsilon = 1e-10): boolean {
|
|
19
|
-
return (
|
|
20
|
-
Math.abs(this.x - euler.x) <= epsilon &&
|
|
21
|
-
Math.abs(this.y - euler.y) <= epsilon &&
|
|
22
|
-
Math.abs(this.z - euler.z) <= epsilon &&
|
|
23
|
-
this.order === euler.order
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
toArray(): [number, number, number] {
|
|
28
|
-
return [this.x, this.y, this.z];
|
|
29
|
-
}
|
|
30
|
-
}
|
package/src/Frustum.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { Box3 } from "./Box3.js";
|
|
2
|
-
import { Matrix4 } from "./Matrix4.js";
|
|
3
|
-
import { Plane } from "./Plane.js";
|
|
4
|
-
import { Sphere } from "./Sphere.js";
|
|
5
|
-
import { Vector3 } from "./Vector3.js";
|
|
6
|
-
|
|
7
|
-
export class Frustum {
|
|
8
|
-
constructor(readonly planes: readonly [Plane, Plane, Plane, Plane, Plane, Plane]) {}
|
|
9
|
-
|
|
10
|
-
static fromMatrix(matrix: Matrix4): Frustum {
|
|
11
|
-
const m = matrix.elements;
|
|
12
|
-
const planes: [Plane, Plane, Plane, Plane, Plane, Plane] = [
|
|
13
|
-
new Plane(new Vector3(m[3] + m[0], m[7] + m[4], m[11] + m[8]), m[15] + m[12]),
|
|
14
|
-
new Plane(new Vector3(m[3] - m[0], m[7] - m[4], m[11] - m[8]), m[15] - m[12]),
|
|
15
|
-
new Plane(new Vector3(m[3] + m[1], m[7] + m[5], m[11] + m[9]), m[15] + m[13]),
|
|
16
|
-
new Plane(new Vector3(m[3] - m[1], m[7] - m[5], m[11] - m[9]), m[15] - m[13]),
|
|
17
|
-
new Plane(new Vector3(m[3] + m[2], m[7] + m[6], m[11] + m[10]), m[15] + m[14]),
|
|
18
|
-
new Plane(new Vector3(m[3] - m[2], m[7] - m[6], m[11] - m[10]), m[15] - m[14])
|
|
19
|
-
];
|
|
20
|
-
return new Frustum(planes);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
containsPoint(point: Vector3): boolean {
|
|
24
|
-
return this.planes.every((plane) => plane.distanceToPoint(point) >= 0);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
intersectsSphere(sphere: Sphere): boolean {
|
|
28
|
-
return this.planes.every((plane) => plane.distanceToPoint(sphere.center) >= -sphere.radius);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
intersectsBox(box: Box3): boolean {
|
|
32
|
-
if (box.isEmpty()) return false;
|
|
33
|
-
for (const plane of this.planes) {
|
|
34
|
-
const p = new Vector3(
|
|
35
|
-
plane.normal.x >= 0 ? box.max.x : box.min.x,
|
|
36
|
-
plane.normal.y >= 0 ? box.max.y : box.min.y,
|
|
37
|
-
plane.normal.z >= 0 ? box.max.z : box.min.z
|
|
38
|
-
);
|
|
39
|
-
if (plane.distanceToPoint(p) < 0) return false;
|
|
40
|
-
}
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
}
|
package/src/Interpolation.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Vector2 } from "./Vector2.js";
|
|
2
|
-
import { Vector3 } from "./Vector3.js";
|
|
3
|
-
import { Vector4 } from "./Vector4.js";
|
|
4
|
-
|
|
5
|
-
export function clamp(value: number, min = 0, max = 1): number {
|
|
6
|
-
if (min > max) throw new RangeError("min must be <= max");
|
|
7
|
-
return Math.min(max, Math.max(min, value));
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function lerp(a: number, b: number, t: number): number {
|
|
11
|
-
return a + (b - a) * t;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export function inverseLerp(a: number, b: number, value: number): number {
|
|
15
|
-
if (a === b) throw new RangeError("inverseLerp requires distinct endpoints");
|
|
16
|
-
return (value - a) / (b - a);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function smoothstep(edge0: number, edge1: number, value: number): number {
|
|
20
|
-
const t = clamp(inverseLerp(edge0, edge1, value));
|
|
21
|
-
return t * t * (3 - 2 * t);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function lerpVector2(a: Vector2, b: Vector2, t: number): Vector2 {
|
|
25
|
-
return a.lerp(b, t);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function lerpVector3(a: Vector3, b: Vector3, t: number): Vector3 {
|
|
29
|
-
return a.lerp(b, t);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function lerpVector4(a: Vector4, b: Vector4, t: number): Vector4 {
|
|
33
|
-
return a.lerp(b, t);
|
|
34
|
-
}
|
package/src/Matrix3.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
export class Matrix3 {
|
|
2
|
-
readonly elements: readonly [number, number, number, number, number, number, number, number, number];
|
|
3
|
-
|
|
4
|
-
constructor(elements?: readonly [number, number, number, number, number, number, number, number, number]) {
|
|
5
|
-
this.elements = elements ? [...elements] as typeof this.elements : [1, 0, 0, 0, 1, 0, 0, 0, 1];
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
determinant(): number {
|
|
9
|
-
const m = this.elements;
|
|
10
|
-
return m[0] * (m[4] * m[8] - m[5] * m[7]) - m[3] * (m[1] * m[8] - m[2] * m[7]) + m[6] * (m[1] * m[5] - m[2] * m[4]);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
inverse(): Matrix3 {
|
|
14
|
-
const m = this.elements;
|
|
15
|
-
const det = this.determinant();
|
|
16
|
-
if (Math.abs(det) < 1e-12) throw new RangeError("Matrix3 is singular.");
|
|
17
|
-
const invDet = 1 / det;
|
|
18
|
-
return new Matrix3([
|
|
19
|
-
(m[4] * m[8] - m[5] * m[7]) * invDet,
|
|
20
|
-
(m[2] * m[7] - m[1] * m[8]) * invDet,
|
|
21
|
-
(m[1] * m[5] - m[2] * m[4]) * invDet,
|
|
22
|
-
(m[5] * m[6] - m[3] * m[8]) * invDet,
|
|
23
|
-
(m[0] * m[8] - m[2] * m[6]) * invDet,
|
|
24
|
-
(m[2] * m[3] - m[0] * m[5]) * invDet,
|
|
25
|
-
(m[3] * m[7] - m[4] * m[6]) * invDet,
|
|
26
|
-
(m[1] * m[6] - m[0] * m[7]) * invDet,
|
|
27
|
-
(m[0] * m[4] - m[1] * m[3]) * invDet
|
|
28
|
-
]);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
multiply(other: Matrix3): Matrix3 {
|
|
32
|
-
const a = this.elements;
|
|
33
|
-
const b = other.elements;
|
|
34
|
-
const out = new Array<number>(9);
|
|
35
|
-
for (let row = 0; row < 3; row++) {
|
|
36
|
-
for (let col = 0; col < 3; col++) {
|
|
37
|
-
out[col * 3 + row] =
|
|
38
|
-
a[0 * 3 + row]! * b[col * 3 + 0]! +
|
|
39
|
-
a[1 * 3 + row]! * b[col * 3 + 1]! +
|
|
40
|
-
a[2 * 3 + row]! * b[col * 3 + 2]!;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return new Matrix3(out as unknown as Matrix3["elements"]);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
transpose(): Matrix3 {
|
|
47
|
-
const m = this.elements;
|
|
48
|
-
return new Matrix3([
|
|
49
|
-
m[0], m[3], m[6],
|
|
50
|
-
m[1], m[4], m[7],
|
|
51
|
-
m[2], m[5], m[8]
|
|
52
|
-
]);
|
|
53
|
-
}
|
|
54
|
-
}
|
package/src/Matrix4.ts
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import { Quaternion } from "./Quaternion.js";
|
|
2
|
-
import { Vector3 } from "./Vector3.js";
|
|
3
|
-
import { Vector4 } from "./Vector4.js";
|
|
4
|
-
|
|
5
|
-
export class Matrix4 {
|
|
6
|
-
readonly elements: readonly [
|
|
7
|
-
number, number, number, number,
|
|
8
|
-
number, number, number, number,
|
|
9
|
-
number, number, number, number,
|
|
10
|
-
number, number, number, number
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
constructor(elements?: Matrix4["elements"]) {
|
|
14
|
-
this.elements = elements ? [...elements] as Matrix4["elements"] : [
|
|
15
|
-
1, 0, 0, 0,
|
|
16
|
-
0, 1, 0, 0,
|
|
17
|
-
0, 0, 1, 0,
|
|
18
|
-
0, 0, 0, 1
|
|
19
|
-
];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
static identity(): Matrix4 {
|
|
23
|
-
return new Matrix4();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
static translation(v: Vector3): Matrix4 {
|
|
27
|
-
return new Matrix4([
|
|
28
|
-
1, 0, 0, 0,
|
|
29
|
-
0, 1, 0, 0,
|
|
30
|
-
0, 0, 1, 0,
|
|
31
|
-
v.x, v.y, v.z, 1
|
|
32
|
-
]);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
static scaling(v: Vector3): Matrix4 {
|
|
36
|
-
return new Matrix4([
|
|
37
|
-
v.x, 0, 0, 0,
|
|
38
|
-
0, v.y, 0, 0,
|
|
39
|
-
0, 0, v.z, 0,
|
|
40
|
-
0, 0, 0, 1
|
|
41
|
-
]);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
static rotation(q: Quaternion): Matrix4 {
|
|
45
|
-
const n = q.normalize();
|
|
46
|
-
const x2 = n.x + n.x;
|
|
47
|
-
const y2 = n.y + n.y;
|
|
48
|
-
const z2 = n.z + n.z;
|
|
49
|
-
const xx = n.x * x2;
|
|
50
|
-
const xy = n.x * y2;
|
|
51
|
-
const xz = n.x * z2;
|
|
52
|
-
const yy = n.y * y2;
|
|
53
|
-
const yz = n.y * z2;
|
|
54
|
-
const zz = n.z * z2;
|
|
55
|
-
const wx = n.w * x2;
|
|
56
|
-
const wy = n.w * y2;
|
|
57
|
-
const wz = n.w * z2;
|
|
58
|
-
return new Matrix4([
|
|
59
|
-
1 - (yy + zz), xy + wz, xz - wy, 0,
|
|
60
|
-
xy - wz, 1 - (xx + zz), yz + wx, 0,
|
|
61
|
-
xz + wy, yz - wx, 1 - (xx + yy), 0,
|
|
62
|
-
0, 0, 0, 1
|
|
63
|
-
]);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
static compose(position: Vector3, rotation: Quaternion, scale: Vector3): Matrix4 {
|
|
67
|
-
return Matrix4.translation(position).multiply(Matrix4.rotation(rotation)).multiply(Matrix4.scaling(scale));
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
static perspective(fovYRadians: number, aspect: number, near: number, far: number): Matrix4 {
|
|
71
|
-
if (![fovYRadians, aspect, near, far].every(Number.isFinite) || fovYRadians <= 0 || aspect <= 0 || near <= 0 || far <= near) {
|
|
72
|
-
throw new RangeError("Invalid perspective projection parameters.");
|
|
73
|
-
}
|
|
74
|
-
const f = 1 / Math.tan(fovYRadians / 2);
|
|
75
|
-
const nf = 1 / (near - far);
|
|
76
|
-
return new Matrix4([
|
|
77
|
-
f / aspect, 0, 0, 0,
|
|
78
|
-
0, f, 0, 0,
|
|
79
|
-
0, 0, (far + near) * nf, -1,
|
|
80
|
-
0, 0, 2 * far * near * nf, 0
|
|
81
|
-
]);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
static orthographic(left: number, right: number, bottom: number, top: number, near: number, far: number): Matrix4 {
|
|
85
|
-
if (![left, right, bottom, top, near, far].every(Number.isFinite) || left === right || bottom === top || near === far) {
|
|
86
|
-
throw new RangeError("Invalid orthographic projection parameters.");
|
|
87
|
-
}
|
|
88
|
-
const lr = 1 / (left - right);
|
|
89
|
-
const bt = 1 / (bottom - top);
|
|
90
|
-
const nf = 1 / (near - far);
|
|
91
|
-
return new Matrix4([
|
|
92
|
-
-2 * lr, 0, 0, 0,
|
|
93
|
-
0, -2 * bt, 0, 0,
|
|
94
|
-
0, 0, 2 * nf, 0,
|
|
95
|
-
(left + right) * lr, (top + bottom) * bt, (far + near) * nf, 1
|
|
96
|
-
]);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
static lookAt(eye: Vector3, target: Vector3, up: Vector3): Matrix4 {
|
|
100
|
-
const z = eye.subtract(target).normalize();
|
|
101
|
-
if (z.lengthSquared() === 0) throw new RangeError("Look-at eye and target must not be identical.");
|
|
102
|
-
|
|
103
|
-
let x = up.cross(z).normalize();
|
|
104
|
-
if (x.lengthSquared() === 0) {
|
|
105
|
-
const fallbackUp = Math.abs(up.z) === 1 ? Vector3.up : Vector3.forward;
|
|
106
|
-
x = fallbackUp.cross(z).normalize();
|
|
107
|
-
}
|
|
108
|
-
const y = z.cross(x).normalize();
|
|
109
|
-
|
|
110
|
-
return new Matrix4([
|
|
111
|
-
x.x, y.x, z.x, 0,
|
|
112
|
-
x.y, y.y, z.y, 0,
|
|
113
|
-
x.z, y.z, z.z, 0,
|
|
114
|
-
-x.dot(eye), -y.dot(eye), -z.dot(eye), 1
|
|
115
|
-
]);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
multiply(other: Matrix4): Matrix4 {
|
|
119
|
-
const a = this.elements;
|
|
120
|
-
const b = other.elements;
|
|
121
|
-
const out = new Array<number>(16);
|
|
122
|
-
for (let row = 0; row < 4; row++) {
|
|
123
|
-
for (let col = 0; col < 4; col++) {
|
|
124
|
-
out[col * 4 + row] =
|
|
125
|
-
a[0 * 4 + row]! * b[col * 4 + 0]! +
|
|
126
|
-
a[1 * 4 + row]! * b[col * 4 + 1]! +
|
|
127
|
-
a[2 * 4 + row]! * b[col * 4 + 2]! +
|
|
128
|
-
a[3 * 4 + row]! * b[col * 4 + 3]!;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return new Matrix4(out as unknown as Matrix4["elements"]);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
transformPoint(v: Vector3): Vector3 {
|
|
135
|
-
const m = this.elements;
|
|
136
|
-
const x = v.x;
|
|
137
|
-
const y = v.y;
|
|
138
|
-
const z = v.z;
|
|
139
|
-
const w = m[3] * x + m[7] * y + m[11] * z + m[15];
|
|
140
|
-
const iw = w === 0 ? 1 : 1 / w;
|
|
141
|
-
return new Vector3(
|
|
142
|
-
(m[0] * x + m[4] * y + m[8] * z + m[12]) * iw,
|
|
143
|
-
(m[1] * x + m[5] * y + m[9] * z + m[13]) * iw,
|
|
144
|
-
(m[2] * x + m[6] * y + m[10] * z + m[14]) * iw
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
transformVector4(v: Vector4): Vector4 {
|
|
149
|
-
const m = this.elements;
|
|
150
|
-
return new Vector4(
|
|
151
|
-
m[0] * v.x + m[4] * v.y + m[8] * v.z + m[12] * v.w,
|
|
152
|
-
m[1] * v.x + m[5] * v.y + m[9] * v.z + m[13] * v.w,
|
|
153
|
-
m[2] * v.x + m[6] * v.y + m[10] * v.z + m[14] * v.w,
|
|
154
|
-
m[3] * v.x + m[7] * v.y + m[11] * v.z + m[15] * v.w
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
transpose(): Matrix4 {
|
|
159
|
-
const m = this.elements;
|
|
160
|
-
return new Matrix4([
|
|
161
|
-
m[0], m[4], m[8], m[12],
|
|
162
|
-
m[1], m[5], m[9], m[13],
|
|
163
|
-
m[2], m[6], m[10], m[14],
|
|
164
|
-
m[3], m[7], m[11], m[15]
|
|
165
|
-
]);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
determinant(): number {
|
|
169
|
-
const m = this.elements;
|
|
170
|
-
const m00 = m[0], m01 = m[4], m02 = m[8], m03 = m[12];
|
|
171
|
-
const m10 = m[1], m11 = m[5], m12 = m[9], m13 = m[13];
|
|
172
|
-
const m20 = m[2], m21 = m[6], m22 = m[10], m23 = m[14];
|
|
173
|
-
const m30 = m[3], m31 = m[7], m32 = m[11], m33 = m[15];
|
|
174
|
-
return (
|
|
175
|
-
m03 * m12 * m21 * m30 - m02 * m13 * m21 * m30 -
|
|
176
|
-
m03 * m11 * m22 * m30 + m01 * m13 * m22 * m30 +
|
|
177
|
-
m02 * m11 * m23 * m30 - m01 * m12 * m23 * m30 -
|
|
178
|
-
m03 * m12 * m20 * m31 + m02 * m13 * m20 * m31 +
|
|
179
|
-
m03 * m10 * m22 * m31 - m00 * m13 * m22 * m31 -
|
|
180
|
-
m02 * m10 * m23 * m31 + m00 * m12 * m23 * m31 +
|
|
181
|
-
m03 * m11 * m20 * m32 - m01 * m13 * m20 * m32 -
|
|
182
|
-
m03 * m10 * m21 * m32 + m00 * m13 * m21 * m32 +
|
|
183
|
-
m01 * m10 * m23 * m32 - m00 * m11 * m23 * m32 -
|
|
184
|
-
m02 * m11 * m20 * m33 + m01 * m12 * m20 * m33 +
|
|
185
|
-
m02 * m10 * m21 * m33 - m00 * m12 * m21 * m33 -
|
|
186
|
-
m01 * m10 * m22 * m33 + m00 * m11 * m22 * m33
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
inverse(): Matrix4 {
|
|
191
|
-
const m = this.elements;
|
|
192
|
-
const inv = new Array<number>(16);
|
|
193
|
-
|
|
194
|
-
inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
|
|
195
|
-
inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
|
|
196
|
-
inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
|
|
197
|
-
inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
|
|
198
|
-
inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
|
|
199
|
-
inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
|
|
200
|
-
inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
|
|
201
|
-
inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
|
|
202
|
-
inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
|
|
203
|
-
inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
|
|
204
|
-
inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
|
|
205
|
-
inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
|
|
206
|
-
inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
|
|
207
|
-
inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
|
|
208
|
-
inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
|
|
209
|
-
inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
|
|
210
|
-
|
|
211
|
-
const det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
|
|
212
|
-
if (Math.abs(det) < 1e-12) throw new RangeError("Matrix4 is singular.");
|
|
213
|
-
return new Matrix4(inv.map((value) => value / det) as unknown as Matrix4["elements"]);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
decompose(): { position: Vector3; rotation: Quaternion; scale: Vector3 } {
|
|
217
|
-
const m = this.elements;
|
|
218
|
-
const position = new Vector3(m[12], m[13], m[14]);
|
|
219
|
-
const sx = new Vector3(m[0], m[1], m[2]).length();
|
|
220
|
-
const sy = new Vector3(m[4], m[5], m[6]).length();
|
|
221
|
-
const sz = new Vector3(m[8], m[9], m[10]).length();
|
|
222
|
-
if (sx === 0 || sy === 0 || sz === 0) throw new RangeError("Cannot decompose matrix with zero scale.");
|
|
223
|
-
|
|
224
|
-
const det = this.determinant();
|
|
225
|
-
const scale = new Vector3(det < 0 ? -sx : sx, sy, sz);
|
|
226
|
-
const rotationMatrix = new Matrix4([
|
|
227
|
-
m[0] / scale.x, m[1] / scale.x, m[2] / scale.x, 0,
|
|
228
|
-
m[4] / scale.y, m[5] / scale.y, m[6] / scale.y, 0,
|
|
229
|
-
m[8] / scale.z, m[9] / scale.z, m[10] / scale.z, 0,
|
|
230
|
-
0, 0, 0, 1
|
|
231
|
-
]);
|
|
232
|
-
|
|
233
|
-
return { position, rotation: Quaternion.fromRotationMatrix(rotationMatrix), scale };
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
getTranslation(): Vector3 {
|
|
237
|
-
const m = this.elements;
|
|
238
|
-
return new Vector3(m[12], m[13], m[14]);
|
|
239
|
-
}
|
|
240
|
-
}
|
package/src/Plane.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Vector3 } from "./Vector3.js";
|
|
2
|
-
|
|
3
|
-
export class Plane {
|
|
4
|
-
readonly normal: Vector3;
|
|
5
|
-
readonly constant: number;
|
|
6
|
-
|
|
7
|
-
constructor(normal = Vector3.up.clone(), constant = 0) {
|
|
8
|
-
const len = normal.length();
|
|
9
|
-
if (len === 0) throw new RangeError("Plane normal must be non-zero.");
|
|
10
|
-
this.normal = normal.multiplyScalar(1 / len);
|
|
11
|
-
this.constant = constant / len;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
static fromPointNormal(point: Vector3, normal: Vector3): Plane {
|
|
15
|
-
const normalized = normal.normalize();
|
|
16
|
-
return new Plane(normalized, -point.dot(normalized));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
distanceToPoint(point: Vector3): number {
|
|
20
|
-
return this.normal.dot(point) + this.constant;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
projectPoint(point: Vector3): Vector3 {
|
|
24
|
-
return point.subtract(this.normal.multiplyScalar(this.distanceToPoint(point)));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
intersectLine(start: Vector3, end: Vector3): Vector3 | undefined {
|
|
28
|
-
const direction = end.subtract(start);
|
|
29
|
-
const denominator = this.normal.dot(direction);
|
|
30
|
-
if (Math.abs(denominator) < 1e-12) return undefined;
|
|
31
|
-
const t = -(start.dot(this.normal) + this.constant) / denominator;
|
|
32
|
-
return t < 0 || t > 1 ? undefined : start.add(direction.multiplyScalar(t));
|
|
33
|
-
}
|
|
34
|
-
}
|
package/src/Quaternion.ts
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { Vector3 } from "./Vector3.js";
|
|
2
|
-
import type { Matrix4 } from "./Matrix4.js";
|
|
3
|
-
|
|
4
|
-
export type EulerOrder = "XYZ";
|
|
5
|
-
|
|
6
|
-
export class Quaternion {
|
|
7
|
-
static readonly identity = Object.freeze(new Quaternion(0, 0, 0, 1));
|
|
8
|
-
|
|
9
|
-
constructor(
|
|
10
|
-
readonly x = 0,
|
|
11
|
-
readonly y = 0,
|
|
12
|
-
readonly z = 0,
|
|
13
|
-
readonly w = 1
|
|
14
|
-
) {}
|
|
15
|
-
|
|
16
|
-
static fromAxisAngle(axis: Vector3, radians: number): Quaternion {
|
|
17
|
-
const normalized = axis.normalize();
|
|
18
|
-
if (normalized.lengthSquared() === 0) throw new RangeError("Axis must be non-zero.");
|
|
19
|
-
const half = radians / 2;
|
|
20
|
-
const s = Math.sin(half);
|
|
21
|
-
return new Quaternion(normalized.x * s, normalized.y * s, normalized.z * s, Math.cos(half)).normalize();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
static fromUnitVectors(from: Vector3, to: Vector3): Quaternion {
|
|
25
|
-
const vFrom = from.normalize();
|
|
26
|
-
const vTo = to.normalize();
|
|
27
|
-
const dot = vFrom.dot(vTo);
|
|
28
|
-
|
|
29
|
-
if (dot < -0.999999) {
|
|
30
|
-
const axis = Math.abs(vFrom.x) > 0.1 ? Vector3.up.cross(vFrom).normalize() : Vector3.right.cross(vFrom).normalize();
|
|
31
|
-
return Quaternion.fromAxisAngle(axis, Math.PI);
|
|
32
|
-
}
|
|
33
|
-
if (dot > 0.999999) return Quaternion.identity.clone();
|
|
34
|
-
|
|
35
|
-
const cross = vFrom.cross(vTo);
|
|
36
|
-
return new Quaternion(cross.x, cross.y, cross.z, 1 + dot).normalize();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
static fromEuler(x: number, y: number, z: number, order: EulerOrder = "XYZ"): Quaternion {
|
|
40
|
-
if (order !== "XYZ") throw new RangeError(`Unsupported Euler order: ${order}`);
|
|
41
|
-
if (![x, y, z].every(Number.isFinite)) throw new RangeError("Euler angles must be finite.");
|
|
42
|
-
const c1 = Math.cos(x / 2);
|
|
43
|
-
const c2 = Math.cos(y / 2);
|
|
44
|
-
const c3 = Math.cos(z / 2);
|
|
45
|
-
const s1 = Math.sin(x / 2);
|
|
46
|
-
const s2 = Math.sin(y / 2);
|
|
47
|
-
const s3 = Math.sin(z / 2);
|
|
48
|
-
return new Quaternion(
|
|
49
|
-
s1 * c2 * c3 + c1 * s2 * s3,
|
|
50
|
-
c1 * s2 * c3 - s1 * c2 * s3,
|
|
51
|
-
c1 * c2 * s3 + s1 * s2 * c3,
|
|
52
|
-
c1 * c2 * c3 - s1 * s2 * s3
|
|
53
|
-
).normalize();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
static fromRotationMatrix(matrix: Matrix4): Quaternion {
|
|
57
|
-
const m = matrix.elements;
|
|
58
|
-
const m11 = m[0]!, m12 = m[4]!, m13 = m[8]!;
|
|
59
|
-
const m21 = m[1]!, m22 = m[5]!, m23 = m[9]!;
|
|
60
|
-
const m31 = m[2]!, m32 = m[6]!, m33 = m[10]!;
|
|
61
|
-
const trace = m11 + m22 + m33;
|
|
62
|
-
|
|
63
|
-
if (trace > 0) {
|
|
64
|
-
const s = 0.5 / Math.sqrt(trace + 1);
|
|
65
|
-
return new Quaternion(
|
|
66
|
-
(m32 - m23) * s,
|
|
67
|
-
(m13 - m31) * s,
|
|
68
|
-
(m21 - m12) * s,
|
|
69
|
-
0.25 / s
|
|
70
|
-
).normalize();
|
|
71
|
-
}
|
|
72
|
-
if (m11 > m22 && m11 > m33) {
|
|
73
|
-
const s = 2 * Math.sqrt(1 + m11 - m22 - m33);
|
|
74
|
-
return new Quaternion(
|
|
75
|
-
0.25 * s,
|
|
76
|
-
(m12 + m21) / s,
|
|
77
|
-
(m13 + m31) / s,
|
|
78
|
-
(m32 - m23) / s
|
|
79
|
-
).normalize();
|
|
80
|
-
}
|
|
81
|
-
if (m22 > m33) {
|
|
82
|
-
const s = 2 * Math.sqrt(1 + m22 - m11 - m33);
|
|
83
|
-
return new Quaternion(
|
|
84
|
-
(m12 + m21) / s,
|
|
85
|
-
0.25 * s,
|
|
86
|
-
(m23 + m32) / s,
|
|
87
|
-
(m13 - m31) / s
|
|
88
|
-
).normalize();
|
|
89
|
-
}
|
|
90
|
-
const s = 2 * Math.sqrt(1 + m33 - m11 - m22);
|
|
91
|
-
return new Quaternion(
|
|
92
|
-
(m13 + m31) / s,
|
|
93
|
-
(m23 + m32) / s,
|
|
94
|
-
0.25 * s,
|
|
95
|
-
(m21 - m12) / s
|
|
96
|
-
).normalize();
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
clone(): Quaternion {
|
|
100
|
-
return new Quaternion(this.x, this.y, this.z, this.w);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
length(): number {
|
|
104
|
-
return Math.hypot(this.x, this.y, this.z, this.w);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
normalize(): Quaternion {
|
|
108
|
-
const len = this.length();
|
|
109
|
-
if (len === 0) return Quaternion.identity.clone();
|
|
110
|
-
return new Quaternion(this.x / len, this.y / len, this.z / len, this.w / len);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
conjugate(): Quaternion {
|
|
114
|
-
return new Quaternion(-this.x, -this.y, -this.z, this.w);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
inverse(): Quaternion {
|
|
118
|
-
const lengthSquared = this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
|
|
119
|
-
if (lengthSquared === 0) return Quaternion.identity.clone();
|
|
120
|
-
const conjugate = this.conjugate();
|
|
121
|
-
return new Quaternion(
|
|
122
|
-
conjugate.x / lengthSquared,
|
|
123
|
-
conjugate.y / lengthSquared,
|
|
124
|
-
conjugate.z / lengthSquared,
|
|
125
|
-
conjugate.w / lengthSquared
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
multiply(q: Quaternion): Quaternion {
|
|
130
|
-
return new Quaternion(
|
|
131
|
-
this.w * q.x + this.x * q.w + this.y * q.z - this.z * q.y,
|
|
132
|
-
this.w * q.y - this.x * q.z + this.y * q.w + this.z * q.x,
|
|
133
|
-
this.w * q.z + this.x * q.y - this.y * q.x + this.z * q.w,
|
|
134
|
-
this.w * q.w - this.x * q.x - this.y * q.y - this.z * q.z
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
rotateVector(v: Vector3): Vector3 {
|
|
139
|
-
const qv = new Quaternion(v.x, v.y, v.z, 0);
|
|
140
|
-
const result = this.multiply(qv).multiply(this.conjugate());
|
|
141
|
-
return new Vector3(result.x, result.y, result.z);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
slerp(to: Quaternion, t: number): Quaternion {
|
|
145
|
-
let target = to;
|
|
146
|
-
let cosHalfTheta = this.x * to.x + this.y * to.y + this.z * to.z + this.w * to.w;
|
|
147
|
-
|
|
148
|
-
if (cosHalfTheta < 0) {
|
|
149
|
-
target = new Quaternion(-to.x, -to.y, -to.z, -to.w);
|
|
150
|
-
cosHalfTheta = -cosHalfTheta;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (cosHalfTheta >= 1.0) return this.clone();
|
|
154
|
-
if (cosHalfTheta > 0.9995) {
|
|
155
|
-
return new Quaternion(
|
|
156
|
-
this.x + t * (target.x - this.x),
|
|
157
|
-
this.y + t * (target.y - this.y),
|
|
158
|
-
this.z + t * (target.z - this.z),
|
|
159
|
-
this.w + t * (target.w - this.w)
|
|
160
|
-
).normalize();
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const halfTheta = Math.acos(cosHalfTheta);
|
|
164
|
-
const sinHalfTheta = Math.sqrt(1 - cosHalfTheta * cosHalfTheta);
|
|
165
|
-
const ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta;
|
|
166
|
-
const ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
|
|
167
|
-
return new Quaternion(
|
|
168
|
-
this.x * ratioA + target.x * ratioB,
|
|
169
|
-
this.y * ratioA + target.y * ratioB,
|
|
170
|
-
this.z * ratioA + target.z * ratioB,
|
|
171
|
-
this.w * ratioA + target.w * ratioB
|
|
172
|
-
).normalize();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
equals(q: Quaternion, epsilon = 1e-10): boolean {
|
|
176
|
-
return Math.abs(this.x - q.x) <= epsilon && Math.abs(this.y - q.y) <= epsilon && Math.abs(this.z - q.z) <= epsilon && Math.abs(this.w - q.w) <= epsilon;
|
|
177
|
-
}
|
|
178
|
-
}
|
package/src/Random.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export class SeededRandom {
|
|
2
|
-
private state: number;
|
|
3
|
-
|
|
4
|
-
constructor(seed: number) {
|
|
5
|
-
if (!Number.isInteger(seed)) throw new RangeError("Seed must be an integer.");
|
|
6
|
-
this.state = seed >>> 0;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
nextUint32(): number {
|
|
10
|
-
let x = this.state;
|
|
11
|
-
x ^= x << 13;
|
|
12
|
-
x ^= x >>> 17;
|
|
13
|
-
x ^= x << 5;
|
|
14
|
-
this.state = x >>> 0;
|
|
15
|
-
return this.state;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
nextFloat(): number {
|
|
19
|
-
return this.nextUint32() / 0x1_0000_0000;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
range(min: number, max: number): number {
|
|
23
|
-
if (min > max) throw new RangeError("min must be <= max");
|
|
24
|
-
return min + (max - min) * this.nextFloat();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
clone(): SeededRandom {
|
|
28
|
-
const random = new SeededRandom(0);
|
|
29
|
-
random.state = this.state;
|
|
30
|
-
return random;
|
|
31
|
-
}
|
|
32
|
-
}
|
package/src/Ray.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { Box3 } from "./Box3.js";
|
|
2
|
-
import { Plane } from "./Plane.js";
|
|
3
|
-
import { Sphere } from "./Sphere.js";
|
|
4
|
-
import { Vector3 } from "./Vector3.js";
|
|
5
|
-
|
|
6
|
-
export class Ray {
|
|
7
|
-
readonly origin: Vector3;
|
|
8
|
-
readonly direction: Vector3;
|
|
9
|
-
|
|
10
|
-
constructor(origin = Vector3.zero.clone(), direction = Vector3.forward.clone()) {
|
|
11
|
-
const normalized = direction.normalize();
|
|
12
|
-
if (normalized.lengthSquared() === 0) throw new RangeError("Ray direction must be non-zero.");
|
|
13
|
-
this.origin = origin;
|
|
14
|
-
this.direction = normalized;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
at(distance: number): Vector3 {
|
|
18
|
-
return this.origin.add(this.direction.multiplyScalar(distance));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
intersectPlane(plane: Plane): Vector3 | undefined {
|
|
22
|
-
const denominator = plane.normal.dot(this.direction);
|
|
23
|
-
if (Math.abs(denominator) < 1e-12) return undefined;
|
|
24
|
-
const distance = -(this.origin.dot(plane.normal) + plane.constant) / denominator;
|
|
25
|
-
return distance < 0 ? undefined : this.at(distance);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
intersectSphere(sphere: Sphere): Vector3 | undefined {
|
|
29
|
-
const l = sphere.center.subtract(this.origin);
|
|
30
|
-
const tca = l.dot(this.direction);
|
|
31
|
-
const d2 = l.dot(l) - tca * tca;
|
|
32
|
-
const radius2 = sphere.radius * sphere.radius;
|
|
33
|
-
if (d2 > radius2) return undefined;
|
|
34
|
-
const thc = Math.sqrt(radius2 - d2);
|
|
35
|
-
const t0 = tca - thc;
|
|
36
|
-
const t1 = tca + thc;
|
|
37
|
-
const distance = t0 >= 0 ? t0 : t1;
|
|
38
|
-
return distance < 0 ? undefined : this.at(distance);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
intersectBox(box: Box3): Vector3 | undefined {
|
|
42
|
-
if (box.isEmpty()) return undefined;
|
|
43
|
-
let tmin = Number.NEGATIVE_INFINITY;
|
|
44
|
-
let tmax = Number.POSITIVE_INFINITY;
|
|
45
|
-
|
|
46
|
-
for (const axis of ["x", "y", "z"] as const) {
|
|
47
|
-
const origin = this.origin[axis];
|
|
48
|
-
const direction = this.direction[axis];
|
|
49
|
-
const min = box.min[axis];
|
|
50
|
-
const max = box.max[axis];
|
|
51
|
-
if (Math.abs(direction) < 1e-12) {
|
|
52
|
-
if (origin < min || origin > max) return undefined;
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
const invD = 1 / direction;
|
|
56
|
-
let t1 = (min - origin) * invD;
|
|
57
|
-
let t2 = (max - origin) * invD;
|
|
58
|
-
if (t1 > t2) [t1, t2] = [t2, t1];
|
|
59
|
-
tmin = Math.max(tmin, t1);
|
|
60
|
-
tmax = Math.min(tmax, t2);
|
|
61
|
-
if (tmin > tmax) return undefined;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const distance = tmin >= 0 ? tmin : tmax;
|
|
65
|
-
return distance < 0 ? undefined : this.at(distance);
|
|
66
|
-
}
|
|
67
|
-
}
|
package/src/Sphere.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Vector3 } from "./Vector3.js";
|
|
2
|
-
|
|
3
|
-
export class Sphere {
|
|
4
|
-
constructor(
|
|
5
|
-
readonly center = Vector3.zero.clone(),
|
|
6
|
-
readonly radius = 0
|
|
7
|
-
) {
|
|
8
|
-
if (!Number.isFinite(radius) || radius < 0) throw new RangeError("Sphere radius must be finite and non-negative.");
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
containsPoint(point: Vector3): boolean {
|
|
12
|
-
return this.center.distanceTo(point) <= this.radius;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
intersectsSphere(other: Sphere): boolean {
|
|
16
|
-
return this.center.distanceTo(other.center) <= this.radius + other.radius;
|
|
17
|
-
}
|
|
18
|
-
}
|
package/src/Transform.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { Matrix4 } from "./Matrix4.js";
|
|
2
|
-
import { Quaternion } from "./Quaternion.js";
|
|
3
|
-
import { Vector3 } from "./Vector3.js";
|
|
4
|
-
|
|
5
|
-
export class Transform {
|
|
6
|
-
constructor(
|
|
7
|
-
readonly position = Vector3.zero.clone(),
|
|
8
|
-
readonly rotation = Quaternion.identity.clone(),
|
|
9
|
-
readonly scale = Vector3.one.clone()
|
|
10
|
-
) {}
|
|
11
|
-
|
|
12
|
-
static identity(): Transform {
|
|
13
|
-
return new Transform();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
toMatrix4(): Matrix4 {
|
|
17
|
-
return Matrix4.compose(this.position, this.rotation, this.scale);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
combine(child: Transform): Transform {
|
|
21
|
-
const scaledPosition = child.position.multiply(this.scale);
|
|
22
|
-
const rotatedPosition = this.rotation.rotateVector(scaledPosition);
|
|
23
|
-
return new Transform(
|
|
24
|
-
this.position.add(rotatedPosition),
|
|
25
|
-
this.rotation.multiply(child.rotation).normalize(),
|
|
26
|
-
this.scale.multiply(child.scale)
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
transformPoint(point: Vector3): Vector3 {
|
|
31
|
-
return this.toMatrix4().transformPoint(point);
|
|
32
|
-
}
|
|
33
|
-
}
|
package/src/Vector2.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
export class Vector2 {
|
|
2
|
-
static readonly zero = Object.freeze(new Vector2(0, 0));
|
|
3
|
-
static readonly one = Object.freeze(new Vector2(1, 1));
|
|
4
|
-
|
|
5
|
-
constructor(
|
|
6
|
-
readonly x = 0,
|
|
7
|
-
readonly y = 0
|
|
8
|
-
) {}
|
|
9
|
-
|
|
10
|
-
clone(): Vector2 {
|
|
11
|
-
return new Vector2(this.x, this.y);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
add(v: Vector2): Vector2 {
|
|
15
|
-
return new Vector2(this.x + v.x, this.y + v.y);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
subtract(v: Vector2): Vector2 {
|
|
19
|
-
return new Vector2(this.x - v.x, this.y - v.y);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
multiplyScalar(scalar: number): Vector2 {
|
|
23
|
-
return new Vector2(this.x * scalar, this.y * scalar);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
divide(v: Vector2): Vector2 {
|
|
27
|
-
return new Vector2(this.x / v.x, this.y / v.y);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
divideScalar(scalar: number): Vector2 {
|
|
31
|
-
return new Vector2(this.x / scalar, this.y / scalar);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
dot(v: Vector2): number {
|
|
35
|
-
return this.x * v.x + this.y * v.y;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
lengthSquared(): number {
|
|
39
|
-
return this.dot(this);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
length(): number {
|
|
43
|
-
return Math.hypot(this.x, this.y);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
normalize(): Vector2 {
|
|
47
|
-
const len = this.length();
|
|
48
|
-
return len === 0 ? Vector2.zero.clone() : this.multiplyScalar(1 / len);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
distanceTo(v: Vector2): number {
|
|
52
|
-
return this.subtract(v).length();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
lerp(v: Vector2, t: number): Vector2 {
|
|
56
|
-
return new Vector2(this.x + (v.x - this.x) * t, this.y + (v.y - this.y) * t);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
equals(v: Vector2, epsilon = 1e-10): boolean {
|
|
60
|
-
return Math.abs(this.x - v.x) <= epsilon && Math.abs(this.y - v.y) <= epsilon;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
toArray(): [number, number] {
|
|
64
|
-
return [this.x, this.y];
|
|
65
|
-
}
|
|
66
|
-
}
|
package/src/Vector3.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import type { Matrix4 } from "./Matrix4.js";
|
|
2
|
-
import type { Quaternion } from "./Quaternion.js";
|
|
3
|
-
|
|
4
|
-
export class Vector3 {
|
|
5
|
-
static readonly zero = Object.freeze(new Vector3(0, 0, 0));
|
|
6
|
-
static readonly one = Object.freeze(new Vector3(1, 1, 1));
|
|
7
|
-
static readonly up = Object.freeze(new Vector3(0, 1, 0));
|
|
8
|
-
static readonly right = Object.freeze(new Vector3(1, 0, 0));
|
|
9
|
-
static readonly forward = Object.freeze(new Vector3(0, 0, -1));
|
|
10
|
-
|
|
11
|
-
constructor(
|
|
12
|
-
readonly x = 0,
|
|
13
|
-
readonly y = 0,
|
|
14
|
-
readonly z = 0
|
|
15
|
-
) {}
|
|
16
|
-
|
|
17
|
-
clone(): Vector3 {
|
|
18
|
-
return new Vector3(this.x, this.y, this.z);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
add(v: Vector3): Vector3 {
|
|
22
|
-
return new Vector3(this.x + v.x, this.y + v.y, this.z + v.z);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
subtract(v: Vector3): Vector3 {
|
|
26
|
-
return new Vector3(this.x - v.x, this.y - v.y, this.z - v.z);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
multiplyScalar(scalar: number): Vector3 {
|
|
30
|
-
return new Vector3(this.x * scalar, this.y * scalar, this.z * scalar);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
multiply(v: Vector3): Vector3 {
|
|
34
|
-
return new Vector3(this.x * v.x, this.y * v.y, this.z * v.z);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
divide(v: Vector3): Vector3 {
|
|
38
|
-
return new Vector3(this.x / v.x, this.y / v.y, this.z / v.z);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
divideScalar(scalar: number): Vector3 {
|
|
42
|
-
return new Vector3(this.x / scalar, this.y / scalar, this.z / scalar);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
dot(v: Vector3): number {
|
|
46
|
-
return this.x * v.x + this.y * v.y + this.z * v.z;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
cross(v: Vector3): Vector3 {
|
|
50
|
-
return new Vector3(
|
|
51
|
-
this.y * v.z - this.z * v.y,
|
|
52
|
-
this.z * v.x - this.x * v.z,
|
|
53
|
-
this.x * v.y - this.y * v.x
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
lengthSquared(): number {
|
|
58
|
-
return this.dot(this);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
length(): number {
|
|
62
|
-
return Math.hypot(this.x, this.y, this.z);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
normalize(): Vector3 {
|
|
66
|
-
const len = this.length();
|
|
67
|
-
return len === 0 ? Vector3.zero.clone() : this.multiplyScalar(1 / len);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
distanceTo(v: Vector3): number {
|
|
71
|
-
return this.subtract(v).length();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
lerp(v: Vector3, t: number): Vector3 {
|
|
75
|
-
return new Vector3(this.x + (v.x - this.x) * t, this.y + (v.y - this.y) * t, this.z + (v.z - this.z) * t);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
transformMatrix4(matrix: Matrix4): Vector3 {
|
|
79
|
-
return matrix.transformPoint(this);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
rotateByQuaternion(rotation: Quaternion): Vector3 {
|
|
83
|
-
return rotation.rotateVector(this);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
min(v: Vector3): Vector3 {
|
|
87
|
-
return new Vector3(Math.min(this.x, v.x), Math.min(this.y, v.y), Math.min(this.z, v.z));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
max(v: Vector3): Vector3 {
|
|
91
|
-
return new Vector3(Math.max(this.x, v.x), Math.max(this.y, v.y), Math.max(this.z, v.z));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
equals(v: Vector3, epsilon = 1e-10): boolean {
|
|
95
|
-
return Math.abs(this.x - v.x) <= epsilon && Math.abs(this.y - v.y) <= epsilon && Math.abs(this.z - v.z) <= epsilon;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
toArray(): [number, number, number] {
|
|
99
|
-
return [this.x, this.y, this.z];
|
|
100
|
-
}
|
|
101
|
-
}
|
package/src/Vector4.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { Matrix4 } from "./Matrix4.js";
|
|
2
|
-
|
|
3
|
-
export class Vector4 {
|
|
4
|
-
constructor(
|
|
5
|
-
readonly x = 0,
|
|
6
|
-
readonly y = 0,
|
|
7
|
-
readonly z = 0,
|
|
8
|
-
readonly w = 0
|
|
9
|
-
) {}
|
|
10
|
-
|
|
11
|
-
add(v: Vector4): Vector4 {
|
|
12
|
-
return new Vector4(this.x + v.x, this.y + v.y, this.z + v.z, this.w + v.w);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
subtract(v: Vector4): Vector4 {
|
|
16
|
-
return new Vector4(this.x - v.x, this.y - v.y, this.z - v.z, this.w - v.w);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
multiplyScalar(scalar: number): Vector4 {
|
|
20
|
-
return new Vector4(this.x * scalar, this.y * scalar, this.z * scalar, this.w * scalar);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
divide(v: Vector4): Vector4 {
|
|
24
|
-
return new Vector4(this.x / v.x, this.y / v.y, this.z / v.z, this.w / v.w);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
divideScalar(scalar: number): Vector4 {
|
|
28
|
-
return new Vector4(this.x / scalar, this.y / scalar, this.z / scalar, this.w / scalar);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
dot(v: Vector4): number {
|
|
32
|
-
return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
lerp(v: Vector4, t: number): Vector4 {
|
|
36
|
-
return new Vector4(
|
|
37
|
-
this.x + (v.x - this.x) * t,
|
|
38
|
-
this.y + (v.y - this.y) * t,
|
|
39
|
-
this.z + (v.z - this.z) * t,
|
|
40
|
-
this.w + (v.w - this.w) * t
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
transformMatrix4(matrix: Matrix4): Vector4 {
|
|
45
|
-
return matrix.transformVector4(this);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
equals(v: Vector4, epsilon = 1e-10): boolean {
|
|
49
|
-
return Math.abs(this.x - v.x) <= epsilon && Math.abs(this.y - v.y) <= epsilon && Math.abs(this.z - v.z) <= epsilon && Math.abs(this.w - v.w) <= epsilon;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
toArray(): [number, number, number, number] {
|
|
53
|
-
return [this.x, this.y, this.z, this.w];
|
|
54
|
-
}
|
|
55
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export * from "./Vector2.js";
|
|
2
|
-
export * from "./Vector3.js";
|
|
3
|
-
export * from "./Vector4.js";
|
|
4
|
-
export * from "./Matrix3.js";
|
|
5
|
-
export * from "./Matrix4.js";
|
|
6
|
-
export * from "./Quaternion.js";
|
|
7
|
-
export * from "./Euler.js";
|
|
8
|
-
export * from "./Color.js";
|
|
9
|
-
export * from "./Ray.js";
|
|
10
|
-
export * from "./Plane.js";
|
|
11
|
-
export * from "./Box3.js";
|
|
12
|
-
export * from "./Sphere.js";
|
|
13
|
-
export * from "./Frustum.js";
|
|
14
|
-
export * from "./Transform.js";
|
|
15
|
-
export * from "./Interpolation.js";
|
|
16
|
-
export * from "./Easing.js";
|
|
17
|
-
export * from "./Random.js";
|
|
18
|
-
export * from "./Curves.js";
|