@aura3d/scene 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 +36 -4
- package/src/Bounds.ts +0 -68
- package/src/Camera.ts +0 -56
- package/src/DirectionalLight.ts +0 -13
- package/src/Hierarchy.ts +0 -20
- package/src/Layers.ts +0 -24
- package/src/Light.ts +0 -27
- package/src/Lights.ts +0 -5
- package/src/MathTypes.ts +0 -157
- package/src/Object3D.ts +0 -149
- package/src/OrthographicCamera.ts +0 -73
- package/src/PerspectiveCamera.ts +0 -54
- package/src/PointLight.ts +0 -25
- package/src/Renderable.ts +0 -71
- package/src/Scene.ts +0 -134
- package/src/SceneMetadata.ts +0 -225
- package/src/SceneNode.ts +0 -139
- package/src/SceneQuery.ts +0 -39
- package/src/SceneSerializer.ts +0 -177
- package/src/SpotLight.ts +0 -39
- package/src/TransformNode.ts +0 -116
- package/src/index.ts +0 -20
- package/tests/scene.test.ts +0 -117
- package/tsconfig.json +0 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aura3d/scene",
|
|
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",
|
|
@@ -12,7 +12,39 @@
|
|
|
12
12
|
},
|
|
13
13
|
"sideEffects": false,
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@aura3d/core": "1.
|
|
16
|
-
"@aura3d/math": "1.
|
|
17
|
-
}
|
|
15
|
+
"@aura3d/core": "1.4.1",
|
|
16
|
+
"@aura3d/math": "1.4.1"
|
|
17
|
+
},
|
|
18
|
+
"description": "Transform hierarchy, scene nodes, bounds, traversal, queries, cameras, lights, renderable descriptors, scene registry, and serialization for Aura3D.",
|
|
19
|
+
"keywords": [
|
|
20
|
+
"aura3d",
|
|
21
|
+
"3d",
|
|
22
|
+
"browser-3d",
|
|
23
|
+
"web-3d",
|
|
24
|
+
"typescript",
|
|
25
|
+
"scene",
|
|
26
|
+
"scene-graph",
|
|
27
|
+
"transforms",
|
|
28
|
+
"camera",
|
|
29
|
+
"lights",
|
|
30
|
+
"serialization",
|
|
31
|
+
"renderables"
|
|
32
|
+
],
|
|
33
|
+
"homepage": "https://aura3d.auraone.ai",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/auraoneai/aura3d.git",
|
|
37
|
+
"directory": "packages/scene"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/auraoneai/aura3d/issues"
|
|
41
|
+
},
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"README.md",
|
|
48
|
+
"dist"
|
|
49
|
+
]
|
|
18
50
|
}
|
package/src/Bounds.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { Box3, Vector3 } from "@aura3d/math";
|
|
2
|
-
import { transformPoint, type Mat4, type Vec3 } from "./MathTypes.js";
|
|
3
|
-
|
|
4
|
-
export class Bounds3 {
|
|
5
|
-
min: Vec3;
|
|
6
|
-
max: Vec3;
|
|
7
|
-
|
|
8
|
-
constructor(min: Vec3 = [Infinity, Infinity, Infinity], max: Vec3 = [-Infinity, -Infinity, -Infinity]) {
|
|
9
|
-
this.min = [...min] as Vec3;
|
|
10
|
-
this.max = [...max] as Vec3;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
static fromCenterSize(center: Vec3, size: Vec3): Bounds3 {
|
|
14
|
-
return new Bounds3(
|
|
15
|
-
[center[0] - size[0] / 2, center[1] - size[1] / 2, center[2] - size[2] / 2],
|
|
16
|
-
[center[0] + size[0] / 2, center[1] + size[1] / 2, center[2] + size[2] / 2]
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
static fromMathBox(box: Box3): Bounds3 {
|
|
21
|
-
return new Bounds3(box.min.toArray(), box.max.toArray());
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
isEmpty(): boolean {
|
|
25
|
-
return this.toMathBox().isEmpty();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
union(other: Bounds3): Bounds3 {
|
|
29
|
-
return Bounds3.fromMathBox(this.toMathBox().union(other.toMathBox()));
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
intersects(other: Bounds3): boolean {
|
|
33
|
-
return this.toMathBox().intersectsBox(other.toMathBox());
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
containsPoint(point: Vec3): boolean {
|
|
37
|
-
return this.toMathBox().containsPoint(new Vector3(point[0], point[1], point[2]));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
transform(matrix: Mat4): Bounds3 {
|
|
41
|
-
if (this.isEmpty()) return new Bounds3();
|
|
42
|
-
const corners: Vec3[] = [
|
|
43
|
-
[this.min[0], this.min[1], this.min[2]],
|
|
44
|
-
[this.max[0], this.min[1], this.min[2]],
|
|
45
|
-
[this.min[0], this.max[1], this.min[2]],
|
|
46
|
-
[this.min[0], this.min[1], this.max[2]],
|
|
47
|
-
[this.max[0], this.max[1], this.min[2]],
|
|
48
|
-
[this.max[0], this.min[1], this.max[2]],
|
|
49
|
-
[this.min[0], this.max[1], this.max[2]],
|
|
50
|
-
[this.max[0], this.max[1], this.max[2]]
|
|
51
|
-
];
|
|
52
|
-
return corners.reduce((bounds, corner) => bounds.includePoint(transformPoint(matrix, corner)), new Bounds3());
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
includePoint(point: Vec3): Bounds3 {
|
|
56
|
-
this.min = [Math.min(this.min[0], point[0]), Math.min(this.min[1], point[1]), Math.min(this.min[2], point[2])];
|
|
57
|
-
this.max = [Math.max(this.max[0], point[0]), Math.max(this.max[1], point[1]), Math.max(this.max[2], point[2])];
|
|
58
|
-
return this;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
clone(): Bounds3 {
|
|
62
|
-
return new Bounds3(this.min, this.max);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
toMathBox(): Box3 {
|
|
66
|
-
return new Box3(new Vector3(this.min[0], this.min[1], this.min[2]), new Vector3(this.max[0], this.max[1], this.max[2]));
|
|
67
|
-
}
|
|
68
|
-
}
|
package/src/Camera.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { ValidationError } from "@aura3d/core";
|
|
2
|
-
import { Frustum } from "@aura3d/math";
|
|
3
|
-
import { extractFrustumPlanes, identityMat4, multiplyMat4, toMathMat4, type Mat4, type PlaneTuple } from "./MathTypes.js";
|
|
4
|
-
import { SceneNode } from "./SceneNode.js";
|
|
5
|
-
|
|
6
|
-
export interface CameraViewport {
|
|
7
|
-
x: number;
|
|
8
|
-
y: number;
|
|
9
|
-
width: number;
|
|
10
|
-
height: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export abstract class Camera extends SceneNode {
|
|
14
|
-
viewport: CameraViewport = { x: 0, y: 0, width: 1, height: 1 };
|
|
15
|
-
readonly frustumPlanes: PlaneTuple[] = [];
|
|
16
|
-
frustum: Frustum = Frustum.fromMatrix(toMathMat4(identityMat4()));
|
|
17
|
-
projectionMatrix: Mat4;
|
|
18
|
-
viewMatrix: Mat4;
|
|
19
|
-
viewProjectionMatrix: Mat4;
|
|
20
|
-
|
|
21
|
-
protected constructor(name: string, id?: string) {
|
|
22
|
-
super({ id, name });
|
|
23
|
-
this.projectionMatrix = identityMat4();
|
|
24
|
-
this.viewMatrix = this.transform.inverseWorldMatrix;
|
|
25
|
-
this.viewProjectionMatrix = multiplyMat4(this.projectionMatrix, this.viewMatrix);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
abstract computeProjectionMatrix(): Mat4;
|
|
29
|
-
|
|
30
|
-
updateCameraMatrices(): void {
|
|
31
|
-
updateAncestors(this);
|
|
32
|
-
this.updateWorldTransform();
|
|
33
|
-
this.projectionMatrix = this.computeProjectionMatrix();
|
|
34
|
-
this.viewMatrix = this.transform.inverseWorldMatrix;
|
|
35
|
-
this.viewProjectionMatrix = multiplyMat4(this.projectionMatrix, this.viewMatrix);
|
|
36
|
-
this.frustum = Frustum.fromMatrix(toMathMat4(this.viewProjectionMatrix));
|
|
37
|
-
this.frustumPlanes.splice(0, this.frustumPlanes.length, ...extractFrustumPlanes(this.viewProjectionMatrix));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
setViewport(viewport: CameraViewport): void {
|
|
41
|
-
if (viewport.width <= 0 || viewport.height <= 0) throw new ValidationError("CAMERA_VIEWPORT", "Camera viewport dimensions must be positive.");
|
|
42
|
-
this.viewport = { ...viewport };
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function updateAncestors(node: SceneNode): void {
|
|
47
|
-
const ancestors: SceneNode[] = [];
|
|
48
|
-
let parent = node.parent;
|
|
49
|
-
while (parent) {
|
|
50
|
-
ancestors.unshift(parent);
|
|
51
|
-
parent = parent.parent;
|
|
52
|
-
}
|
|
53
|
-
for (const ancestor of ancestors) {
|
|
54
|
-
ancestor.transform.updateWorld(ancestor.parent?.transform.worldMatrix);
|
|
55
|
-
}
|
|
56
|
-
}
|
package/src/DirectionalLight.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { normalizeVec3, type Vec3 } from "./MathTypes.js";
|
|
2
|
-
import { Light } from "./Light.js";
|
|
3
|
-
|
|
4
|
-
export class DirectionalLight extends Light {
|
|
5
|
-
constructor(name = "DirectionalLight", id?: string) {
|
|
6
|
-
super("directional", name, id);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
getDirection(): Vec3 {
|
|
10
|
-
const m = this.transform.worldMatrix;
|
|
11
|
-
return normalizeVec3([-m[8], -m[9], -m[10]]);
|
|
12
|
-
}
|
|
13
|
-
}
|
package/src/Hierarchy.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { assertCanParent, type AddChildOptions, type SceneNode } from "./SceneNode.js";
|
|
2
|
-
|
|
3
|
-
export function isAncestor(ancestor: SceneNode, node: SceneNode): boolean {
|
|
4
|
-
return ancestor.isAncestorOf(node);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export function reparent(node: SceneNode, newParent: SceneNode, options: AddChildOptions = {}): void {
|
|
8
|
-
assertCanParent(newParent, node);
|
|
9
|
-
newParent.addChild(node, options);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function batchReparent(nodes: readonly SceneNode[], newParent: SceneNode, options: AddChildOptions = {}): void {
|
|
13
|
-
for (const node of nodes) reparent(node, newParent, options);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function removeAllChildren(node: SceneNode): SceneNode[] {
|
|
17
|
-
const removed = [...node.children];
|
|
18
|
-
for (const child of removed) node.removeChild(child);
|
|
19
|
-
return removed;
|
|
20
|
-
}
|
package/src/Layers.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export class Layers {
|
|
2
|
-
mask = 1;
|
|
3
|
-
|
|
4
|
-
set(channel: number): void {
|
|
5
|
-
this.mask = 1 << validateChannel(channel);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
enable(channel: number): void {
|
|
9
|
-
this.mask |= 1 << validateChannel(channel);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
disable(channel: number): void {
|
|
13
|
-
this.mask &= ~(1 << validateChannel(channel));
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
test(other: Layers): boolean {
|
|
17
|
-
return (this.mask & other.mask) !== 0;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function validateChannel(channel: number): number {
|
|
22
|
-
if (!Number.isInteger(channel) || channel < 0 || channel > 31) throw new Error("Layer channel must be an integer in [0, 31].");
|
|
23
|
-
return channel;
|
|
24
|
-
}
|
package/src/Light.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { ValidationError } from "@aura3d/core";
|
|
2
|
-
import { type Vector3 } from "@aura3d/math";
|
|
3
|
-
import { type Vec3 } from "./MathTypes.js";
|
|
4
|
-
import { SceneNode } from "./SceneNode.js";
|
|
5
|
-
|
|
6
|
-
export type LightKind = "directional" | "point" | "spot";
|
|
7
|
-
|
|
8
|
-
export abstract class Light extends SceneNode {
|
|
9
|
-
readonly kind: LightKind;
|
|
10
|
-
color: Vec3 | Vector3 = [1, 1, 1];
|
|
11
|
-
castsShadow = false;
|
|
12
|
-
private currentIntensity = 1;
|
|
13
|
-
|
|
14
|
-
protected constructor(kind: LightKind, name: string, id?: string) {
|
|
15
|
-
super({ id, name });
|
|
16
|
-
this.kind = kind;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
get intensity(): number {
|
|
20
|
-
return this.currentIntensity;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
set intensity(value: number) {
|
|
24
|
-
if (!(value >= 0) || !Number.isFinite(value)) throw new ValidationError("LIGHT_INTENSITY", "Light intensity must be a finite non-negative number.");
|
|
25
|
-
this.currentIntensity = value;
|
|
26
|
-
}
|
|
27
|
-
}
|
package/src/Lights.ts
DELETED
package/src/MathTypes.ts
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { Frustum, Matrix4, Quaternion, Vector3 } from "@aura3d/math";
|
|
2
|
-
|
|
3
|
-
export type Vec3 = [number, number, number];
|
|
4
|
-
export type Quat = [number, number, number, number];
|
|
5
|
-
export type Mat4 = [
|
|
6
|
-
number, number, number, number,
|
|
7
|
-
number, number, number, number,
|
|
8
|
-
number, number, number, number,
|
|
9
|
-
number, number, number, number
|
|
10
|
-
];
|
|
11
|
-
export type PlaneTuple = [number, number, number, number];
|
|
12
|
-
|
|
13
|
-
export const EPSILON = 1e-8;
|
|
14
|
-
|
|
15
|
-
export function vec3(x = 0, y = 0, z = 0): Vec3 {
|
|
16
|
-
return [x, y, z];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function quat(x = 0, y = 0, z = 0, w = 1): Quat {
|
|
20
|
-
return fromMathQuat(new Quaternion(x, y, z, w).normalize());
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function identityMat4(): Mat4 {
|
|
24
|
-
return fromMathMat4(Matrix4.identity());
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function cloneMat4(value: Mat4): Mat4 {
|
|
28
|
-
return [...value] as Mat4;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function addVec3(a: Vec3, b: Vec3): Vec3 {
|
|
32
|
-
return toMathVec3(a).add(toMathVec3(b)).toArray();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function subVec3(a: Vec3, b: Vec3): Vec3 {
|
|
36
|
-
return toMathVec3(a).subtract(toMathVec3(b)).toArray();
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function scaleVec3(a: Vec3, scalar: number): Vec3 {
|
|
40
|
-
return toMathVec3(a).multiplyScalar(scalar).toArray();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function lengthVec3(a: Vec3): number {
|
|
44
|
-
return toMathVec3(a).length();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function normalizeVec3(a: Vec3): Vec3 {
|
|
48
|
-
return toMathVec3(a).normalize().toArray();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function normalizeQuat(value: Quat): Quat {
|
|
52
|
-
return fromMathQuat(toMathQuat(value).normalize());
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function quatFromEuler(x: number, y: number, z: number): Quat {
|
|
56
|
-
const sx = Math.sin(x / 2);
|
|
57
|
-
const cx = Math.cos(x / 2);
|
|
58
|
-
const sy = Math.sin(y / 2);
|
|
59
|
-
const cy = Math.cos(y / 2);
|
|
60
|
-
const sz = Math.sin(z / 2);
|
|
61
|
-
const cz = Math.cos(z / 2);
|
|
62
|
-
return quat(
|
|
63
|
-
sx * cy * cz + cx * sy * sz,
|
|
64
|
-
cx * sy * cz - sx * cy * sz,
|
|
65
|
-
cx * cy * sz + sx * sy * cz,
|
|
66
|
-
cx * cy * cz - sx * sy * sz
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function multiplyMat4(a: Mat4, b: Mat4): Mat4 {
|
|
71
|
-
return fromMathMat4(toMathMat4(a).multiply(toMathMat4(b)));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function composeMat4(position: Vec3, rotation: Quat, scale: Vec3): Mat4 {
|
|
75
|
-
return fromMathMat4(Matrix4.compose(toMathVec3(position), toMathQuat(rotation), toMathVec3(scale)));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export function transformPoint(matrix: Mat4, point: Vec3): Vec3 {
|
|
79
|
-
return toMathMat4(matrix).transformPoint(toMathVec3(point)).toArray();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function invertMat4(matrix: Mat4): Mat4 {
|
|
83
|
-
return fromMathMat4(toMathMat4(matrix).inverse());
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function perspectiveMat4(fovYRadians: number, aspect: number, near: number, far: number): Mat4 {
|
|
87
|
-
return fromMathMat4(Matrix4.perspective(fovYRadians, aspect, near, far));
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function orthographicMat4(left: number, right: number, bottom: number, top: number, near: number, far: number): Mat4 {
|
|
91
|
-
return fromMathMat4(Matrix4.orthographic(left, right, bottom, top, near, far));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export function extractFrustumPlanes(viewProjection: Mat4): PlaneTuple[] {
|
|
95
|
-
return Frustum.fromMatrix(toMathMat4(viewProjection)).planes.map((plane) => [
|
|
96
|
-
plane.normal.x,
|
|
97
|
-
plane.normal.y,
|
|
98
|
-
plane.normal.z,
|
|
99
|
-
plane.constant
|
|
100
|
-
]);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export function toMathVec3(value: Vec3): Vector3 {
|
|
104
|
-
return new Vector3(value[0], value[1], value[2]);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function toMathQuat(value: Quat): Quaternion {
|
|
108
|
-
return new Quaternion(value[0], value[1], value[2], value[3]);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function toMathMat4(value: Mat4): Matrix4 {
|
|
112
|
-
return new Matrix4(value);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export function fromMathMat4(value: Matrix4): Mat4 {
|
|
116
|
-
return [...value.elements] as Mat4;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export function fromMathQuat(value: Quaternion): Quat {
|
|
120
|
-
return [value.x, value.y, value.z, value.w];
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
export function decomposeMat4(matrix: Mat4): { position: Vec3; rotation: Quat; scale: Vec3 } {
|
|
124
|
-
const position: Vec3 = [matrix[12], matrix[13], matrix[14]];
|
|
125
|
-
const sx = Math.hypot(matrix[0], matrix[1], matrix[2]);
|
|
126
|
-
const sy = Math.hypot(matrix[4], matrix[5], matrix[6]);
|
|
127
|
-
const sz = Math.hypot(matrix[8], matrix[9], matrix[10]);
|
|
128
|
-
if (sx <= EPSILON || sy <= EPSILON || sz <= EPSILON) throw new Error("Cannot decompose transform matrix with zero scale.");
|
|
129
|
-
|
|
130
|
-
const m00 = matrix[0] / sx;
|
|
131
|
-
const m01 = matrix[4] / sy;
|
|
132
|
-
const m02 = matrix[8] / sz;
|
|
133
|
-
const m10 = matrix[1] / sx;
|
|
134
|
-
const m11 = matrix[5] / sy;
|
|
135
|
-
const m12 = matrix[9] / sz;
|
|
136
|
-
const m20 = matrix[2] / sx;
|
|
137
|
-
const m21 = matrix[6] / sy;
|
|
138
|
-
const m22 = matrix[10] / sz;
|
|
139
|
-
const trace = m00 + m11 + m22;
|
|
140
|
-
let rotation: Quat;
|
|
141
|
-
|
|
142
|
-
if (trace > 0) {
|
|
143
|
-
const s = Math.sqrt(trace + 1) * 2;
|
|
144
|
-
rotation = [(m21 - m12) / s, (m02 - m20) / s, (m10 - m01) / s, 0.25 * s];
|
|
145
|
-
} else if (m00 > m11 && m00 > m22) {
|
|
146
|
-
const s = Math.sqrt(1 + m00 - m11 - m22) * 2;
|
|
147
|
-
rotation = [0.25 * s, (m01 + m10) / s, (m02 + m20) / s, (m21 - m12) / s];
|
|
148
|
-
} else if (m11 > m22) {
|
|
149
|
-
const s = Math.sqrt(1 + m11 - m00 - m22) * 2;
|
|
150
|
-
rotation = [(m01 + m10) / s, 0.25 * s, (m12 + m21) / s, (m02 - m20) / s];
|
|
151
|
-
} else {
|
|
152
|
-
const s = Math.sqrt(1 + m22 - m00 - m11) * 2;
|
|
153
|
-
rotation = [(m02 + m20) / s, (m12 + m21) / s, 0.25 * s, (m10 - m01) / s];
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return { position, rotation: normalizeQuat(rotation), scale: [sx, sy, sz] };
|
|
157
|
-
}
|
package/src/Object3D.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { SceneNode, type SceneNodeOptions } from "./SceneNode.js";
|
|
2
|
-
import { Renderable, type RenderableDescriptor } from "./Renderable.js";
|
|
3
|
-
import type { Mat4, Quat, Vec3 } from "./MathTypes.js";
|
|
4
|
-
|
|
5
|
-
export interface Object3DOptions extends SceneNodeOptions {
|
|
6
|
-
readonly visible?: boolean;
|
|
7
|
-
readonly layerMask?: number;
|
|
8
|
-
readonly renderOrder?: number;
|
|
9
|
-
readonly userData?: Record<string, unknown>;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export class Object3D extends SceneNode {
|
|
13
|
-
readonly isObject3D = true;
|
|
14
|
-
|
|
15
|
-
constructor(options: Object3DOptions = {}) {
|
|
16
|
-
super(options);
|
|
17
|
-
applyObject3DOptions(this, options);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
get position(): Vec3 {
|
|
21
|
-
return this.transform.position;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
get quaternion(): Quat {
|
|
25
|
-
return this.transform.rotation;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
get scale(): Vec3 {
|
|
29
|
-
return this.transform.scale;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get matrix(): Mat4 {
|
|
33
|
-
return this.transform.localMatrix;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
get matrixWorld(): Mat4 {
|
|
37
|
-
return this.transform.worldMatrix;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
get matrixAutoUpdate(): boolean {
|
|
41
|
-
return this.transform.matrixAutoUpdate;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
set matrixAutoUpdate(enabled: boolean) {
|
|
45
|
-
this.transform.setMatrixAutoUpdate(enabled);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
setLocalMatrix(matrix: Mat4, options: { readonly decompose?: boolean; readonly matrixAutoUpdate?: boolean } = {}): this {
|
|
49
|
-
this.transform.setLocalMatrix(matrix, options);
|
|
50
|
-
return this;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export class Group extends Object3D {
|
|
55
|
-
readonly isGroup = true;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface MeshOptions extends Object3DOptions {
|
|
59
|
-
readonly renderable?: Renderable | RenderableDescriptor;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export class Mesh extends Object3D {
|
|
63
|
-
readonly isMesh = true;
|
|
64
|
-
|
|
65
|
-
constructor(options: MeshOptions = {}) {
|
|
66
|
-
super(options);
|
|
67
|
-
if (options.renderable) this.renderable = toRenderable(options.renderable);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
setRenderable(renderable: Renderable | RenderableDescriptor): this {
|
|
71
|
-
this.renderable = toRenderable(renderable);
|
|
72
|
-
return this;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export class SkinnedMesh extends Mesh {
|
|
77
|
-
readonly isSkinnedMesh = true;
|
|
78
|
-
|
|
79
|
-
get skinning(): Renderable["skinning"] | undefined {
|
|
80
|
-
return this.renderable?.skinning;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
setSkinning(skinning: NonNullable<Renderable["skinning"]>): this {
|
|
84
|
-
if (!this.renderable) throw new Error("SkinnedMesh requires a renderable before skinning can be assigned.");
|
|
85
|
-
this.renderable.skinning = {
|
|
86
|
-
jointCount: skinning.jointCount,
|
|
87
|
-
matrices: new Float32Array(skinning.matrices)
|
|
88
|
-
};
|
|
89
|
-
return this;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export class InstancedMesh extends Mesh {
|
|
94
|
-
readonly isInstancedMesh = true;
|
|
95
|
-
|
|
96
|
-
get instanceTransforms(): Float32Array | undefined {
|
|
97
|
-
return this.renderable?.instanceTransforms;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
get instanceColors(): Float32Array | undefined {
|
|
101
|
-
return this.renderable?.instanceColors;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
setInstanceTransforms(transforms: Float32Array | readonly number[]): this {
|
|
105
|
-
if (!this.renderable) throw new Error("InstancedMesh requires a renderable before instance transforms can be assigned.");
|
|
106
|
-
this.renderable.instanceTransforms = new Renderable({
|
|
107
|
-
geometry: this.renderable.geometry,
|
|
108
|
-
material: this.renderable.material,
|
|
109
|
-
layerMask: this.renderable.layerMask,
|
|
110
|
-
castShadow: this.renderable.castShadow,
|
|
111
|
-
receiveShadow: this.renderable.receiveShadow,
|
|
112
|
-
skinning: this.renderable.skinning,
|
|
113
|
-
morphWeights: this.renderable.morphWeights,
|
|
114
|
-
instanceTransforms: transforms,
|
|
115
|
-
instanceColors: this.renderable.instanceColors
|
|
116
|
-
}).instanceTransforms;
|
|
117
|
-
return this;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
setInstanceColors(colors: Float32Array | readonly number[]): this {
|
|
121
|
-
if (!this.renderable) throw new Error("InstancedMesh requires a renderable before instance colors can be assigned.");
|
|
122
|
-
this.renderable.instanceColors = new Renderable({
|
|
123
|
-
geometry: this.renderable.geometry,
|
|
124
|
-
material: this.renderable.material,
|
|
125
|
-
layerMask: this.renderable.layerMask,
|
|
126
|
-
castShadow: this.renderable.castShadow,
|
|
127
|
-
receiveShadow: this.renderable.receiveShadow,
|
|
128
|
-
skinning: this.renderable.skinning,
|
|
129
|
-
morphWeights: this.renderable.morphWeights,
|
|
130
|
-
instanceTransforms: this.renderable.instanceTransforms,
|
|
131
|
-
instanceColors: colors
|
|
132
|
-
}).instanceColors;
|
|
133
|
-
return this;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function applyObject3DOptions(node: SceneNode, options: Object3DOptions): void {
|
|
138
|
-
if (options.visible !== undefined) node.visible = options.visible;
|
|
139
|
-
if (options.layerMask !== undefined) node.layerMask = options.layerMask;
|
|
140
|
-
if (options.renderOrder !== undefined) {
|
|
141
|
-
if (!Number.isFinite(options.renderOrder)) throw new Error("Object3D renderOrder must be finite.");
|
|
142
|
-
node.renderOrder = options.renderOrder;
|
|
143
|
-
}
|
|
144
|
-
if (options.userData) node.userData = { ...options.userData };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function toRenderable(renderable: Renderable | RenderableDescriptor): Renderable {
|
|
148
|
-
return renderable instanceof Renderable ? renderable : new Renderable(renderable);
|
|
149
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { ValidationError } from "@aura3d/core";
|
|
2
|
-
import { orthographicMat4, type Mat4 } from "./MathTypes.js";
|
|
3
|
-
import { Camera } from "./Camera.js";
|
|
4
|
-
|
|
5
|
-
export interface OrthographicCameraOptions {
|
|
6
|
-
id?: string;
|
|
7
|
-
name?: string;
|
|
8
|
-
left?: number;
|
|
9
|
-
right?: number;
|
|
10
|
-
bottom?: number;
|
|
11
|
-
top?: number;
|
|
12
|
-
near?: number;
|
|
13
|
-
far?: number;
|
|
14
|
-
zoom?: number;
|
|
15
|
-
resizeMode?: OrthographicResizeMode;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export type OrthographicResizeMode = "fit-vertical" | "fit-horizontal" | "preserve-frustum";
|
|
19
|
-
|
|
20
|
-
export class OrthographicCamera extends Camera {
|
|
21
|
-
left: number;
|
|
22
|
-
right: number;
|
|
23
|
-
bottom: number;
|
|
24
|
-
top: number;
|
|
25
|
-
near: number;
|
|
26
|
-
far: number;
|
|
27
|
-
zoom: number;
|
|
28
|
-
resizeMode: OrthographicResizeMode;
|
|
29
|
-
|
|
30
|
-
constructor(options: OrthographicCameraOptions = {}) {
|
|
31
|
-
super(options.name ?? "OrthographicCamera", options.id);
|
|
32
|
-
this.left = options.left ?? -1;
|
|
33
|
-
this.right = options.right ?? 1;
|
|
34
|
-
this.bottom = options.bottom ?? -1;
|
|
35
|
-
this.top = options.top ?? 1;
|
|
36
|
-
this.near = options.near ?? 0.1;
|
|
37
|
-
this.far = options.far ?? 1000;
|
|
38
|
-
this.zoom = options.zoom ?? 1;
|
|
39
|
-
this.resizeMode = options.resizeMode ?? "fit-vertical";
|
|
40
|
-
this.projectionMatrix = this.computeProjectionMatrix();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
computeProjectionMatrix(): Mat4 {
|
|
44
|
-
if (!(this.zoom > 0)) throw new ValidationError("CAMERA_ZOOM", "Orthographic zoom must be positive.");
|
|
45
|
-
return orthographicMat4(this.left / this.zoom, this.right / this.zoom, this.bottom / this.zoom, this.top / this.zoom, this.near, this.far);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
resize(width: number, height: number): void {
|
|
49
|
-
if (width <= 0 || height <= 0) throw new ValidationError("CAMERA_RESIZE", "Orthographic resize dimensions must be positive.");
|
|
50
|
-
const aspect = width / height;
|
|
51
|
-
const centerX = (this.left + this.right) / 2;
|
|
52
|
-
const centerY = (this.bottom + this.top) / 2;
|
|
53
|
-
const halfWidth = (this.right - this.left) / 2;
|
|
54
|
-
const halfHeight = (this.top - this.bottom) / 2;
|
|
55
|
-
if (this.resizeMode === "fit-horizontal") {
|
|
56
|
-
const resizedHalfHeight = halfWidth / aspect;
|
|
57
|
-
this.bottom = centerY - resizedHalfHeight;
|
|
58
|
-
this.top = centerY + resizedHalfHeight;
|
|
59
|
-
} else if (this.resizeMode === "preserve-frustum") {
|
|
60
|
-
const resizedHalfWidth = Math.max(halfWidth, halfHeight * aspect);
|
|
61
|
-
const resizedHalfHeight = Math.max(halfHeight, halfWidth / aspect);
|
|
62
|
-
this.left = centerX - resizedHalfWidth;
|
|
63
|
-
this.right = centerX + resizedHalfWidth;
|
|
64
|
-
this.bottom = centerY - resizedHalfHeight;
|
|
65
|
-
this.top = centerY + resizedHalfHeight;
|
|
66
|
-
} else {
|
|
67
|
-
const resizedHalfWidth = halfHeight * aspect;
|
|
68
|
-
this.left = centerX - resizedHalfWidth;
|
|
69
|
-
this.right = centerX + resizedHalfWidth;
|
|
70
|
-
}
|
|
71
|
-
this.updateCameraMatrices();
|
|
72
|
-
}
|
|
73
|
-
}
|