@flighthq/scene3d 0.2.1-next.840.857425c
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/dist/billboard.d.ts +8 -0
- package/dist/billboard.d.ts.map +1 -0
- package/dist/billboard.js +41 -0
- package/dist/billboard.js.map +1 -0
- package/dist/billboardCamera.d.ts +4 -0
- package/dist/billboardCamera.d.ts.map +1 -0
- package/dist/billboardCamera.js +238 -0
- package/dist/billboardCamera.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/mesh.d.ts +10 -0
- package/dist/mesh.d.ts.map +1 -0
- package/dist/mesh.js +75 -0
- package/dist/mesh.js.map +1 -0
- package/dist/prepareScene3DMorph.d.ts +3 -0
- package/dist/prepareScene3DMorph.d.ts.map +1 -0
- package/dist/prepareScene3DMorph.js +34 -0
- package/dist/prepareScene3DMorph.js.map +1 -0
- package/dist/scene.d.ts +3 -0
- package/dist/scene.d.ts.map +1 -0
- package/dist/scene.js +12 -0
- package/dist/scene.js.map +1 -0
- package/dist/sceneAnimation.d.ts +3 -0
- package/dist/sceneAnimation.d.ts.map +1 -0
- package/dist/sceneAnimation.js +43 -0
- package/dist/sceneAnimation.js.map +1 -0
- package/dist/sceneDocument.d.ts +4 -0
- package/dist/sceneDocument.d.ts.map +1 -0
- package/dist/sceneDocument.js +163 -0
- package/dist/sceneDocument.js.map +1 -0
- package/dist/sceneMaterial.d.ts +4 -0
- package/dist/sceneMaterial.d.ts.map +1 -0
- package/dist/sceneMaterial.js +58 -0
- package/dist/sceneMaterial.js.map +1 -0
- package/dist/sceneNode.d.ts +8 -0
- package/dist/sceneNode.d.ts.map +1 -0
- package/dist/sceneNode.js +29 -0
- package/dist/sceneNode.js.map +1 -0
- package/dist/sceneNodeAppearance.d.ts +5 -0
- package/dist/sceneNodeAppearance.d.ts.map +1 -0
- package/dist/sceneNodeAppearance.js +50 -0
- package/dist/sceneNodeAppearance.js.map +1 -0
- package/dist/sceneNodeBounds.d.ts +3 -0
- package/dist/sceneNodeBounds.d.ts.map +1 -0
- package/dist/sceneNodeBounds.js +49 -0
- package/dist/sceneNodeBounds.js.map +1 -0
- package/dist/sceneNodeCulling.d.ts +4 -0
- package/dist/sceneNodeCulling.d.ts.map +1 -0
- package/dist/sceneNodeCulling.js +62 -0
- package/dist/sceneNodeCulling.js.map +1 -0
- package/dist/sceneNodeDispose.d.ts +3 -0
- package/dist/sceneNodeDispose.d.ts.map +1 -0
- package/dist/sceneNodeDispose.js +15 -0
- package/dist/sceneNodeDispose.js.map +1 -0
- package/dist/sceneNodeTransform.d.ts +3 -0
- package/dist/sceneNodeTransform.d.ts.map +1 -0
- package/dist/sceneNodeTransform.js +65 -0
- package/dist/sceneNodeTransform.js.map +1 -0
- package/package.json +49 -0
- package/src/billboard.test.ts +79 -0
- package/src/billboardCamera.test.ts +152 -0
- package/src/mesh.test.ts +247 -0
- package/src/prepareScene3DMorph.test.ts +68 -0
- package/src/scene.test.ts +53 -0
- package/src/sceneAnimation.test.ts +109 -0
- package/src/sceneDocument.test.ts +173 -0
- package/src/sceneMaterial.test.ts +95 -0
- package/src/sceneNode.test.ts +291 -0
- package/src/sceneNodeAppearance.test.ts +80 -0
- package/src/sceneNodeBounds.test.ts +86 -0
- package/src/sceneNodeCulling.test.ts +123 -0
- package/src/sceneNodeDispose.test.ts +38 -0
- package/src/sceneNodeTransform.test.ts +40 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { createAnimationChannel, createAnimationClip } from '@flighthq/animation';
|
|
2
|
+
import { createEntity } from '@flighthq/entity';
|
|
3
|
+
import { setQuaternion, setVector3 } from '@flighthq/geometry';
|
|
4
|
+
import { addNodeChild, invalidateNodeLocalTransform } from '@flighthq/node';
|
|
5
|
+
import { createMesh } from './mesh';
|
|
6
|
+
import { createScene3D } from './scene';
|
|
7
|
+
import { createNode3D } from './sceneNode';
|
|
8
|
+
// Assembles a Scene3DDocument's scene into a live Scene3D — the inverse of the scene-format parsers, which STOP
|
|
9
|
+
// at the format-neutral Scene3DDocument decomposition rather than building entities inline. This is the single
|
|
10
|
+
// assembler every importer shares: `createScene3DFromGltf` and its siblings are `createScene3DFromDocument(parse
|
|
11
|
+
// <Format>(bytes))`. `sceneIndex` selects which of the document's scenes to build (default the first); the
|
|
12
|
+
// document's animation clips and metadata are attached to it. An empty or scene-less document yields an
|
|
13
|
+
// empty Scene3D.
|
|
14
|
+
//
|
|
15
|
+
// The function is a THIN composition of small per-component steps: build one Node3D per document node
|
|
16
|
+
// (Mesh when the node names a mesh, group otherwise), wire the child index lists, resolve each skin's joint
|
|
17
|
+
// indices to the built nodes, and rebuild each animation clip's channels against them — no format knowledge
|
|
18
|
+
// lives here. Cameras and lights are placement tables the document carries for the caller to read; they are
|
|
19
|
+
// not parented into the graph (a camera is a pure entity, not a scene node), so this assembler leaves them
|
|
20
|
+
// on the document.
|
|
21
|
+
export function createScene3DFromDocument(document, sceneIndex = 0) {
|
|
22
|
+
const nodes = buildDocumentNodes(document);
|
|
23
|
+
applyDocumentSkins(document, nodes);
|
|
24
|
+
const scene = createScene3D();
|
|
25
|
+
const roots = document.scenes[sceneIndex]?.rootNodes ?? [];
|
|
26
|
+
for (let r = 0; r < roots.length; r++) {
|
|
27
|
+
const node = nodes[roots[r]];
|
|
28
|
+
if (node !== undefined)
|
|
29
|
+
addNodeChild(scene.root, node);
|
|
30
|
+
}
|
|
31
|
+
attachDocumentAnimations(document, nodes, scene);
|
|
32
|
+
scene.metadata = document.metadata;
|
|
33
|
+
return scene;
|
|
34
|
+
}
|
|
35
|
+
// Assembles every scene the document declares (each a view of the shared node pool), in declaration order.
|
|
36
|
+
// The document's animation clips and metadata are attached to the default scene (index 0), matching the
|
|
37
|
+
// per-format multi-scene importers. An empty document yields an empty array.
|
|
38
|
+
export function createScene3DsFromDocument(document) {
|
|
39
|
+
const nodes = buildDocumentNodes(document);
|
|
40
|
+
applyDocumentSkins(document, nodes);
|
|
41
|
+
const scenes = [];
|
|
42
|
+
for (let s = 0; s < document.scenes.length; s++) {
|
|
43
|
+
const scene = createScene3D();
|
|
44
|
+
const roots = document.scenes[s].rootNodes;
|
|
45
|
+
for (let r = 0; r < roots.length; r++) {
|
|
46
|
+
const node = nodes[roots[r]];
|
|
47
|
+
if (node !== undefined)
|
|
48
|
+
addNodeChild(scene.root, node);
|
|
49
|
+
}
|
|
50
|
+
scenes.push(scene);
|
|
51
|
+
}
|
|
52
|
+
if (scenes.length > 0) {
|
|
53
|
+
attachDocumentAnimations(document, nodes, scenes[0]);
|
|
54
|
+
scenes[0].metadata = document.metadata;
|
|
55
|
+
}
|
|
56
|
+
return scenes;
|
|
57
|
+
}
|
|
58
|
+
// Applies a document node's authored TRS transform, marking the local matrix stale so the world matrix
|
|
59
|
+
// recomposes from the fields.
|
|
60
|
+
function applyDocumentNodeTransform(node, source) {
|
|
61
|
+
const t = source.transform;
|
|
62
|
+
setVector3(node.position, t.position.x, t.position.y, t.position.z);
|
|
63
|
+
setQuaternion(node.rotation, t.rotation.x, t.rotation.y, t.rotation.z, t.rotation.w);
|
|
64
|
+
setVector3(node.scale, t.scale.x, t.scale.y, t.scale.z);
|
|
65
|
+
invalidateNodeLocalTransform(node);
|
|
66
|
+
}
|
|
67
|
+
// Resolves each document skin's joint node indices to the built nodes, constructs a Skeleton3D (with its
|
|
68
|
+
// flat inverse-bind matrix array), and binds it onto every mesh whose document entry names that skin.
|
|
69
|
+
function applyDocumentSkins(document, nodes) {
|
|
70
|
+
const skins = document.skins.map((skin) => {
|
|
71
|
+
const joints = [];
|
|
72
|
+
const names = [];
|
|
73
|
+
for (let j = 0; j < skin.joints.length; j++) {
|
|
74
|
+
const joint = nodes[skin.joints[j]];
|
|
75
|
+
if (joint !== undefined) {
|
|
76
|
+
joints.push(joint);
|
|
77
|
+
names.push(joint.name ?? '');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const inverseBindMatrices = new Float32Array(joints.length * 16);
|
|
81
|
+
for (let j = 0; j < skin.inverseBind.length && j < joints.length; j++) {
|
|
82
|
+
inverseBindMatrices.set(skin.inverseBind[j].m, j * 16);
|
|
83
|
+
}
|
|
84
|
+
// The Skeleton3D palette (jointMatrices) is filled per-frame by computeSkeleton3DJointMatrices; here it
|
|
85
|
+
// starts zeroed. Built inline through createEntity rather than via @flighthq/skeleton3d because that
|
|
86
|
+
// package depends on @flighthq/scene3d (createMesh/createNode3D), which would form a cycle; the
|
|
87
|
+
// Entity shape invariant still holds at this assembly seam.
|
|
88
|
+
// Joint names are recovered from the resolved joint nodes; null when the source named none.
|
|
89
|
+
const skeleton = createEntity({
|
|
90
|
+
inverseBindMatrices,
|
|
91
|
+
jointMatrices: new Float32Array(joints.length * 16),
|
|
92
|
+
joints,
|
|
93
|
+
names: names.some((name) => name.length > 0) ? names : null,
|
|
94
|
+
});
|
|
95
|
+
return { skeleton, skeletonRoot: null };
|
|
96
|
+
});
|
|
97
|
+
for (let i = 0; i < document.nodes.length; i++) {
|
|
98
|
+
const meshIndex = document.nodes[i].mesh;
|
|
99
|
+
if (meshIndex === undefined)
|
|
100
|
+
continue;
|
|
101
|
+
const skinIndex = document.meshes[meshIndex]?.skin;
|
|
102
|
+
if (skinIndex === undefined)
|
|
103
|
+
continue;
|
|
104
|
+
const skin = skins[skinIndex];
|
|
105
|
+
if (skin !== null)
|
|
106
|
+
nodes[i].skin = skin;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Rebuilds each document animation into a node-bound AnimationClip and keys it into the scene's animation
|
|
110
|
+
// map by name (falling back to `animation${i}`). The document carries each channel's target as a node index
|
|
111
|
+
// plus Scene3DAnimationPath (the animation core's clip is target-free); here they become live
|
|
112
|
+
// Scene3DAnimationTarget bindings against the built nodes.
|
|
113
|
+
function attachDocumentAnimations(document, nodes, scene) {
|
|
114
|
+
for (let a = 0; a < document.animations.length; a++) {
|
|
115
|
+
const source = document.animations[a];
|
|
116
|
+
const channels = [];
|
|
117
|
+
for (let c = 0; c < source.channels.length; c++) {
|
|
118
|
+
const channel = source.channels[c];
|
|
119
|
+
const node = nodes[channel.node];
|
|
120
|
+
if (node === undefined)
|
|
121
|
+
continue;
|
|
122
|
+
const target = { node, path: channel.path };
|
|
123
|
+
channels.push(createAnimationChannel(channel.track, target));
|
|
124
|
+
}
|
|
125
|
+
if (channels.length === 0)
|
|
126
|
+
continue;
|
|
127
|
+
scene.animations[source.name ?? `animation${a}`] = createAnimationClip(channels, source.duration);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Builds one Node3D per document node (a Mesh when the node names a mesh index, a transform-only group
|
|
131
|
+
// otherwise), applies each authored transform, and wires the child index lists — returning the node pool
|
|
132
|
+
// that skins and animations resolve their indices against. Node identity never leaves the assembler; the
|
|
133
|
+
// document addresses everything by index.
|
|
134
|
+
function buildDocumentNodes(document) {
|
|
135
|
+
const meshes = document.meshes;
|
|
136
|
+
// A document's materials are stored as plain-data MaterialLike, but the importers fill them with real
|
|
137
|
+
// entity-backed materials (createStandardPbrMaterial etc.); treat them as Material for assembly.
|
|
138
|
+
const materials = document.materials;
|
|
139
|
+
const nodes = document.nodes.map((node) => buildDocumentNode(node, meshes, materials));
|
|
140
|
+
for (let i = 0; i < document.nodes.length; i++) {
|
|
141
|
+
applyDocumentNodeTransform(nodes[i], document.nodes[i]);
|
|
142
|
+
const children = document.nodes[i].children;
|
|
143
|
+
for (let c = 0; c < children.length; c++) {
|
|
144
|
+
const child = nodes[children[c]];
|
|
145
|
+
if (child !== undefined)
|
|
146
|
+
addNodeChild(nodes[i], child);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return nodes;
|
|
150
|
+
}
|
|
151
|
+
// Builds a single node: a Mesh (with its inline geometry, resolved materials, and morph) when the node
|
|
152
|
+
// names a mesh index, or a bare transform-only Node3D otherwise.
|
|
153
|
+
function buildDocumentNode(node, meshes, materials) {
|
|
154
|
+
if (node.mesh === undefined)
|
|
155
|
+
return createNode3D(node.kind, { name: node.name });
|
|
156
|
+
const documentMesh = meshes[node.mesh];
|
|
157
|
+
const meshMaterials = documentMesh.materials.map((index) => materials[index] ?? null);
|
|
158
|
+
const mesh = createMesh(documentMesh.geometry, meshMaterials, node.kind, { name: node.name });
|
|
159
|
+
if (documentMesh.morph != null)
|
|
160
|
+
mesh.morph = documentMesh.morph;
|
|
161
|
+
return mesh;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=sceneDocument.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneDocument.js","sourceRoot":"","sources":["../src/sceneDocument.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Material, Node3D } from '@flighthq/types';
|
|
2
|
+
export declare function findScene3DMaterialByName(root: Readonly<Node3D>, name: string): Material | null;
|
|
3
|
+
export declare function getScene3DMaterials(root: Readonly<Node3D>, out: Material[]): void;
|
|
4
|
+
//# sourceMappingURL=sceneMaterial.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneMaterial.d.ts","sourceRoot":"","sources":["../src/sceneMaterial.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAQ,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAS9D,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAW/F;AAQD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,IAAI,CAGjF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { findNode, forEachNodeDescendant } from '@flighthq/node';
|
|
2
|
+
// Finds the first material named `name` in the scene subtree rooted at `root` (depth-first
|
|
3
|
+
// pre-order, `root` included), scanning each mesh node's `materials` array. Returns `null` when no
|
|
4
|
+
// material carries that name. The 3D importers preserve each format's authored material identity
|
|
5
|
+
// (an MTL `newmtl`, a glTF `material.name`, a 3DS material chunk, an MD2/MD5 skin path) on
|
|
6
|
+
// `Material.name`, so a caller can address an imported material by its artist-given handle — for
|
|
7
|
+
// example to tweak transparency — instead of matching on observable traits. The material sibling
|
|
8
|
+
// of node's findNodeByName.
|
|
9
|
+
export function findScene3DMaterialByName(root, name) {
|
|
10
|
+
const rootMatch = getNamedNodeMaterial(root, name);
|
|
11
|
+
if (rootMatch !== null)
|
|
12
|
+
return rootMatch;
|
|
13
|
+
let found = null;
|
|
14
|
+
findNode(root, (node) => {
|
|
15
|
+
const match = getNamedNodeMaterial(node, name);
|
|
16
|
+
if (match === null)
|
|
17
|
+
return false;
|
|
18
|
+
found = match;
|
|
19
|
+
return true;
|
|
20
|
+
});
|
|
21
|
+
return found;
|
|
22
|
+
}
|
|
23
|
+
// Collects every distinct material used in the scene subtree rooted at `root` (depth-first,
|
|
24
|
+
// `root` included) into `out`, scanning each mesh node's `materials` array and skipping nulls and
|
|
25
|
+
// by-reference duplicates (a material shared across meshes appears once). Appends to `out` without
|
|
26
|
+
// clearing it. The bulk sibling of findScene3DMaterialByName: the enumeration a caller walks after
|
|
27
|
+
// import to inspect or re-derive the materials a format produced (pair with getMaterialOfKind to
|
|
28
|
+
// read a specific kind's fields). Order is the depth-first visitation order of first appearance.
|
|
29
|
+
export function getScene3DMaterials(root, out) {
|
|
30
|
+
collectNodeMaterials(root, out);
|
|
31
|
+
forEachNodeDescendant(root, (node) => collectNodeMaterials(node, out));
|
|
32
|
+
}
|
|
33
|
+
// Appends `node`'s own not-yet-collected materials to `out`. Only mesh-like nodes (drawable leaves)
|
|
34
|
+
// carry `materials`; a bare group node reads through as absent.
|
|
35
|
+
function collectNodeMaterials(node, out) {
|
|
36
|
+
const materials = node.materials;
|
|
37
|
+
if (materials == null)
|
|
38
|
+
return;
|
|
39
|
+
for (let i = 0; i < materials.length; i++) {
|
|
40
|
+
const material = materials[i];
|
|
41
|
+
if (material !== null && !out.includes(material))
|
|
42
|
+
out.push(material);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Returns the first material named `name` on `node`'s own `materials` array, or `null`. Only
|
|
46
|
+
// mesh-like nodes (drawable leaves) carry `materials`; a bare group node reads through as absent.
|
|
47
|
+
function getNamedNodeMaterial(node, name) {
|
|
48
|
+
const materials = node.materials;
|
|
49
|
+
if (materials == null)
|
|
50
|
+
return null;
|
|
51
|
+
for (let i = 0; i < materials.length; i++) {
|
|
52
|
+
const material = materials[i];
|
|
53
|
+
if (material !== null && material.name === name)
|
|
54
|
+
return material;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=sceneMaterial.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneMaterial.js","sourceRoot":"","sources":["../src/sceneMaterial.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAGjE,2FAA2F;AAC3F,mGAAmG;AACnG,iGAAiG;AACjG,2FAA2F;AAC3F,iGAAiG;AACjG,iGAAiG;AACjG,4BAA4B;AAC5B,MAAM,UAAU,yBAAyB,CAAC,IAAsB,EAAE,IAAY;IAC5E,MAAM,SAAS,GAAG,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnD,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACzC,IAAI,KAAK,GAAoB,IAAI,CAAC;IAClC,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;QACtB,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAwB,EAAE,IAAI,CAAC,CAAC;QACnE,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACjC,KAAK,GAAG,KAAK,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,4FAA4F;AAC5F,kGAAkG;AAClG,mGAAmG;AACnG,mGAAmG;AACnG,iGAAiG;AACjG,iGAAiG;AACjG,MAAM,UAAU,mBAAmB,CAAC,IAAsB,EAAE,GAAe;IACzE,oBAAoB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAChC,qBAAqB,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,oBAAoB,CAAC,IAAwB,EAAE,GAAG,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,oGAAoG;AACpG,gEAAgE;AAChE,SAAS,oBAAoB,CAAC,IAAsB,EAAE,GAAe;IACnE,MAAM,SAAS,GAAI,IAAgC,CAAC,SAAS,CAAC;IAC9D,IAAI,SAAS,IAAI,IAAI;QAAE,OAAO;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED,6FAA6F;AAC7F,kGAAkG;AAClG,SAAS,oBAAoB,CAAC,IAAsB,EAAE,IAAY;IAChE,MAAM,SAAS,GAAI,IAAgC,CAAC,SAAS,CAAC;IAC9D,IAAI,SAAS,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI;YAAE,OAAO,QAAQ,CAAC;IACnE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Kind, NodeSignals, Node3D, Node3DRuntime } from '@flighthq/types';
|
|
2
|
+
export { Node3DKind } from '@flighthq/types';
|
|
3
|
+
export declare function createNode3D(kind?: Kind, obj?: Readonly<Partial<Pick<Node3D, 'alpha' | 'enabled' | 'name' | 'visible'>>>): Node3D;
|
|
4
|
+
export declare function createNode3DRuntime(): Node3DRuntime;
|
|
5
|
+
export declare function enableNode3DSignals(source: Node3D): NodeSignals;
|
|
6
|
+
export declare function getNode3DRuntime(source: Readonly<Node3D>): Node3DRuntime;
|
|
7
|
+
export declare function getNode3DSignals(source: Node3D): NodeSignals | null;
|
|
8
|
+
//# sourceMappingURL=sceneNode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNode.d.ts","sourceRoot":"","sources":["../src/sceneNode.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAgB,MAAM,iBAAiB,CAAC;AAG9F,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,wBAAgB,YAAY,CAC1B,IAAI,GAAE,IAAiB,EACvB,GAAG,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,GAC9E,MAAM,CAKR;AAED,wBAAgB,mBAAmB,IAAI,aAAa,CASnD;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAE/D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,aAAa,CAExE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAEnE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createNode, createNodeRuntime, enableNodeSignals, getNodeRuntime, getNodeSignals, initAppearanceTrait, initTransform3DRuntimeTrait, initTransform3DTrait, } from '@flighthq/node';
|
|
2
|
+
import { Node3DKind, Node3DTraitsKey } from '@flighthq/types';
|
|
3
|
+
export { Node3DKind } from '@flighthq/types';
|
|
4
|
+
export function createNode3D(kind = Node3DKind, obj) {
|
|
5
|
+
const node = createNode(kind, obj, undefined, createNode3DRuntime);
|
|
6
|
+
initAppearanceTrait(node, obj);
|
|
7
|
+
initTransform3DTrait(node);
|
|
8
|
+
return node;
|
|
9
|
+
}
|
|
10
|
+
export function createNode3DRuntime() {
|
|
11
|
+
const out = createNodeRuntime();
|
|
12
|
+
out.traits = Node3DTraitsKey;
|
|
13
|
+
out.worldAlpha = null;
|
|
14
|
+
out.worldAlphaUsingAppearanceId = -1;
|
|
15
|
+
out.worldAlphaUsingParentAppearanceId = -1;
|
|
16
|
+
out.worldAppearanceId = 0;
|
|
17
|
+
initTransform3DRuntimeTrait(out);
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
export function enableNode3DSignals(source) {
|
|
21
|
+
return enableNodeSignals(source);
|
|
22
|
+
}
|
|
23
|
+
export function getNode3DRuntime(source) {
|
|
24
|
+
return getNodeRuntime(source);
|
|
25
|
+
}
|
|
26
|
+
export function getNode3DSignals(source) {
|
|
27
|
+
return getNodeSignals(source);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=sceneNode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNode.js","sourceRoot":"","sources":["../src/sceneNode.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,2BAA2B,EAC3B,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,UAAU,YAAY,CAC1B,OAAa,UAAU,EACvB,GAA+E;IAE/E,MAAM,IAAI,GAAG,UAAU,CAAe,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;IACjF,mBAAmB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/B,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAC3B,OAAO,IAAc,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,MAAM,GAAG,GAAG,iBAAiB,EAAiC,CAAC;IAC/D,GAAG,CAAC,MAAM,GAAG,eAAe,CAAC;IAC7B,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC;IACtB,GAAG,CAAC,2BAA2B,GAAG,CAAC,CAAC,CAAC;IACrC,GAAG,CAAC,iCAAiC,GAAG,CAAC,CAAC,CAAC;IAC3C,GAAG,CAAC,iBAAiB,GAAG,CAAC,CAAC;IAC1B,2BAA2B,CAAC,GAAG,CAAC,CAAC;IACjC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAwB;IACvD,OAAO,cAAc,CAAC,MAAM,CAAkB,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Node3D } from '@flighthq/types';
|
|
2
|
+
export declare function ensureNode3DWorldAlpha(source: Readonly<Node3D>): void;
|
|
3
|
+
export declare function getNode3DWorldAlpha(source: Readonly<Node3D>): number;
|
|
4
|
+
export declare function setNode3DAlpha(source: Node3D, alpha: number): void;
|
|
5
|
+
//# sourceMappingURL=sceneNodeAppearance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNodeAppearance.d.ts","sourceRoot":"","sources":["../src/sceneNodeAppearance.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAQ9C,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CA6BrE;AAID,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,CAGpE;AAKD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAGlE"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { getNodeAppearanceRevision, invalidateNodeAppearance } from '@flighthq/node';
|
|
2
|
+
import { getNode3DRuntime } from './sceneNode';
|
|
3
|
+
// Ensures the node's resolved parent×self opacity (`worldAlpha`) is current, recomputing only when the
|
|
4
|
+
// node's own appearance revision or an ancestor's resolved appearance changed. Mirrors
|
|
5
|
+
// ensureNodeWorldMatrix4: walks the parent chain, caches on the runtime, and gates on revision ids —
|
|
6
|
+
// so worldAlpha is correct on demand, not only mid-render, and a clean node costs nothing to read.
|
|
7
|
+
export function ensureNode3DWorldAlpha(source) {
|
|
8
|
+
const runtime = getNode3DRuntime(source);
|
|
9
|
+
const parent = runtime.parent;
|
|
10
|
+
let parentWorldAlpha = 1;
|
|
11
|
+
let parentWorldAppearanceId = 0;
|
|
12
|
+
if (parent !== null) {
|
|
13
|
+
ensureNode3DWorldAlpha(parent);
|
|
14
|
+
const parentRuntime = getNode3DRuntime(parent);
|
|
15
|
+
parentWorldAlpha = parentRuntime.worldAlpha;
|
|
16
|
+
parentWorldAppearanceId = parentRuntime.worldAppearanceId;
|
|
17
|
+
}
|
|
18
|
+
const appearanceId = getNodeAppearanceRevision(source);
|
|
19
|
+
if (runtime.worldAlpha === null ||
|
|
20
|
+
runtime.worldAlphaUsingAppearanceId !== appearanceId ||
|
|
21
|
+
runtime.worldAlphaUsingParentAppearanceId !== parentWorldAppearanceId) {
|
|
22
|
+
runtime.worldAlpha = parentWorldAlpha * source.alpha;
|
|
23
|
+
runtime.worldAlphaUsingAppearanceId = appearanceId;
|
|
24
|
+
runtime.worldAlphaUsingParentAppearanceId = parentWorldAppearanceId;
|
|
25
|
+
// A fresh monotonic revision per recompute, mirroring computeNodeWorldTransformRevision: a composite
|
|
26
|
+
// of (appearanceId, parentWorldAppearanceId) is lossy and would not carry a grandparent's alpha change
|
|
27
|
+
// down to a grandchild, so the resolved id must change unconditionally whenever worldAlpha recomputes.
|
|
28
|
+
_worldAppearanceRevisionCounter = (_worldAppearanceRevisionCounter + 1) >>> 0;
|
|
29
|
+
if (_worldAppearanceRevisionCounter === 0)
|
|
30
|
+
_worldAppearanceRevisionCounter = 1;
|
|
31
|
+
runtime.worldAppearanceId = _worldAppearanceRevisionCounter;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// The resolved parent×self opacity the renderer honors per Mesh. Ensures on access (like
|
|
35
|
+
// getNodeWorldMatrix4), so it is correct whenever queried — 1 for a node with no appearance.
|
|
36
|
+
export function getNode3DWorldAlpha(source) {
|
|
37
|
+
ensureNode3DWorldAlpha(source);
|
|
38
|
+
return getNode3DRuntime(source).worldAlpha ?? 1;
|
|
39
|
+
}
|
|
40
|
+
// Sets the node's own opacity and invalidates its appearance so the resolved worldAlpha (and its
|
|
41
|
+
// descendants') recomputes on next access. The appearance counterpart of writing a transform field
|
|
42
|
+
// and calling invalidateNodeLocalTransform.
|
|
43
|
+
export function setNode3DAlpha(source, alpha) {
|
|
44
|
+
source.alpha = alpha;
|
|
45
|
+
invalidateNodeAppearance(source);
|
|
46
|
+
}
|
|
47
|
+
// Monotonic source of resolved-appearance revisions, shared across nodes so a parent recompute always
|
|
48
|
+
// yields an id its children have not seen. Runtime-only (never serialized); wraps at 32 bits.
|
|
49
|
+
let _worldAppearanceRevisionCounter = 0;
|
|
50
|
+
//# sourceMappingURL=sceneNodeAppearance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNodeAppearance.js","sourceRoot":"","sources":["../src/sceneNodeAppearance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAGrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,uGAAuG;AACvG,uFAAuF;AACvF,qGAAqG;AACrG,mGAAmG;AACnG,MAAM,UAAU,sBAAsB,CAAC,MAAwB;IAC7D,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAuB,CAAC;IAE/C,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,IAAI,uBAAuB,GAAG,CAAC,CAAC;IAChC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAC/B,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC/C,gBAAgB,GAAG,aAAa,CAAC,UAAW,CAAC;QAC7C,uBAAuB,GAAG,aAAa,CAAC,iBAAiB,CAAC;IAC5D,CAAC;IAED,MAAM,YAAY,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IACvD,IACE,OAAO,CAAC,UAAU,KAAK,IAAI;QAC3B,OAAO,CAAC,2BAA2B,KAAK,YAAY;QACpD,OAAO,CAAC,iCAAiC,KAAK,uBAAuB,EACrE,CAAC;QACD,OAAO,CAAC,UAAU,GAAG,gBAAgB,GAAG,MAAM,CAAC,KAAK,CAAC;QACrD,OAAO,CAAC,2BAA2B,GAAG,YAAY,CAAC;QACnD,OAAO,CAAC,iCAAiC,GAAG,uBAAuB,CAAC;QACpE,qGAAqG;QACrG,uGAAuG;QACvG,uGAAuG;QACvG,+BAA+B,GAAG,CAAC,+BAA+B,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAC9E,IAAI,+BAA+B,KAAK,CAAC;YAAE,+BAA+B,GAAG,CAAC,CAAC;QAC/E,OAAO,CAAC,iBAAiB,GAAG,+BAA+B,CAAC;IAC9D,CAAC;AACH,CAAC;AAED,yFAAyF;AACzF,6FAA6F;AAC7F,MAAM,UAAU,mBAAmB,CAAC,MAAwB;IAC1D,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,iGAAiG;AACjG,mGAAmG;AACnG,4CAA4C;AAC5C,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,KAAa;IAC1D,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC;AAED,sGAAsG;AACtG,8FAA8F;AAC9F,IAAI,+BAA+B,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNodeBounds.d.ts","sourceRoot":"","sources":["../src/sceneNodeBounds.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAsBxD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAYhF"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createAabb, setAabb, transformAabbByMatrix4, unionAabb } from '@flighthq/geometry';
|
|
2
|
+
import { ensureMeshGeometryBounds } from '@flighthq/mesh';
|
|
3
|
+
import { ensureNodeWorldMatrix4, getNodeRuntime, getNodeWorldMatrix4 } from '@flighthq/node';
|
|
4
|
+
import { isMesh } from './mesh';
|
|
5
|
+
// Accumulates the world-space AABB of `node` and all of its descendants into `out`. Each Mesh
|
|
6
|
+
// leaf contributes its local-space geometry bounds transformed by its world matrix. Transform-only
|
|
7
|
+
// group nodes with no Mesh geometry contribute nothing. Disabled nodes (`enabled === false`) are
|
|
8
|
+
// still included — filter them in the visitor if you need to exclude them.
|
|
9
|
+
//
|
|
10
|
+
// If neither `node` nor any descendant is a Mesh, `out` is set to an empty box
|
|
11
|
+
// (min = +Infinity, max = -Infinity). The result is in world space.
|
|
12
|
+
//
|
|
13
|
+
// SKINNED MESHES CONTRIBUTE THEIR BIND-POSE BOX, NOT THEIR POSED ONE. A GPU-skinned mesh deforms in
|
|
14
|
+
// the shader, so its geometry keeps bind-pose vertices and that is what this unions. The posed bound
|
|
15
|
+
// needs the joint palette, which lives in @flighthq/skeleton3d — a layer this package sits below and
|
|
16
|
+
// must not reach up into. A caller that needs posed-accurate aggregation composes the two itself at a
|
|
17
|
+
// layer that sees both (this walk for rigid/morphed nodes, getMeshDeformedLocalBounds per skinned
|
|
18
|
+
// node); a caller fitting a volume around the result absorbs pose excursions with padding instead.
|
|
19
|
+
//
|
|
20
|
+
// Alias-safe: reads all geometry bounds and world transforms before accumulating into `out`.
|
|
21
|
+
// Skinned meshes contribute their bind-pose geometry extents. Posed-accurate aggregate bounds are
|
|
22
|
+
// caller composition above the scene layer; shadow fits can use padding to absorb pose excursions.
|
|
23
|
+
export function getNode3DWorldBounds(out, node) {
|
|
24
|
+
// Reset to empty before accumulation.
|
|
25
|
+
setAabb(out, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY);
|
|
26
|
+
_accumulateWorldBounds(out, node);
|
|
27
|
+
}
|
|
28
|
+
function _accumulateWorldBounds(out, node) {
|
|
29
|
+
if (isMesh(node)) {
|
|
30
|
+
// Read through the ensure, never `geometry.bounds` directly: bounds are a dirty-gated cache that a
|
|
31
|
+
// deform invalidates by bumping the version, so a raw field read can return a pre-deform box.
|
|
32
|
+
const localBounds = ensureMeshGeometryBounds(node.geometry);
|
|
33
|
+
// Only add a non-empty local bounds to the world accumulator.
|
|
34
|
+
if (localBounds !== null && localBounds.min.x <= localBounds.max.x) {
|
|
35
|
+
ensureNodeWorldMatrix4(node);
|
|
36
|
+
const worldMatrix = getNodeWorldMatrix4(node);
|
|
37
|
+
transformAabbByMatrix4(_scratchWorldAabb, localBounds, worldMatrix);
|
|
38
|
+
unionAabb(out, out, _scratchWorldAabb);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const children = getNodeRuntime(node).children;
|
|
42
|
+
if (children !== null) {
|
|
43
|
+
for (let i = 0; i < children.length; i++) {
|
|
44
|
+
_accumulateWorldBounds(out, children[i]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const _scratchWorldAabb = createAabb();
|
|
49
|
+
//# sourceMappingURL=sceneNodeBounds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNodeBounds.js","sourceRoot":"","sources":["../src/sceneNodeBounds.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC5F,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG7F,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,8FAA8F;AAC9F,mGAAmG;AACnG,iGAAiG;AACjG,2EAA2E;AAC3E,EAAE;AACF,+EAA+E;AAC/E,oEAAoE;AACpE,EAAE;AACF,oGAAoG;AACpG,qGAAqG;AACrG,qGAAqG;AACrG,sGAAsG;AACtG,kGAAkG;AAClG,mGAAmG;AACnG,EAAE;AACF,6FAA6F;AAC7F,kGAAkG;AAClG,mGAAmG;AACnG,MAAM,UAAU,oBAAoB,CAAC,GAAa,EAAE,IAAsB;IACxE,sCAAsC;IACtC,OAAO,CACL,GAAG,EACH,MAAM,CAAC,iBAAiB,EACxB,MAAM,CAAC,iBAAiB,EACxB,MAAM,CAAC,iBAAiB,EACxB,MAAM,CAAC,iBAAiB,EACxB,MAAM,CAAC,iBAAiB,EACxB,MAAM,CAAC,iBAAiB,CACzB,CAAC;IACF,sBAAsB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,sBAAsB,CAAC,GAAa,EAAE,IAAsB;IACnE,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QACjB,mGAAmG;QACnG,8FAA8F;QAC9F,MAAM,WAAW,GAAG,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5D,8DAA8D;QAC9D,IAAI,WAAW,KAAK,IAAI,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACnE,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAC9C,sBAAsB,CAAC,iBAAiB,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;YACpE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IACD,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC;IAC/C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,sBAAsB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAW,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,iBAAiB,GAAG,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FrustumLike, Matrix4Like, Node3D } from '@flighthq/types';
|
|
2
|
+
export declare function buildScene3DFrustum(out: FrustumLike, viewProjection: Readonly<Matrix4Like>): void;
|
|
3
|
+
export declare function cullNode3DByFrustum(out: Node3D[], root: Readonly<Node3D>, frustum: Readonly<FrustumLike>): Node3D[];
|
|
4
|
+
//# sourceMappingURL=sceneNodeCulling.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNodeCulling.d.ts","sourceRoot":"","sources":["../src/sceneNodeCulling.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAYxE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,IAAI,CAEjG;AAaD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,WAAW,CAAC,GAAG,MAAM,EAAE,CAGnH"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { createAabb, isFrustumIntersectingAabb, setFrustumFromMatrix4, transformAabbByMatrix4, } from '@flighthq/geometry';
|
|
2
|
+
import { computeMeshGeometryBounds } from '@flighthq/mesh';
|
|
3
|
+
import { ensureNodeWorldMatrix4, getNodeRuntime, getNodeWorldMatrix4 } from '@flighthq/node';
|
|
4
|
+
import { isMesh } from './mesh';
|
|
5
|
+
// Convenience: derives a camera frustum from a view-projection matrix and calls
|
|
6
|
+
// `cullNode3DByFrustum`. `viewProjection` must be the combined view × projection matrix
|
|
7
|
+
// (as returned by getCamera3DViewProjectionMatrix4). Writes the derived frustum into `outFrustum`
|
|
8
|
+
// so the caller can cache it for the frame (pass createFrustum() or a scratch Frustum).
|
|
9
|
+
//
|
|
10
|
+
// `aspect` is intentionally absent here — the caller provides the pre-computed viewProjection.
|
|
11
|
+
// For camera-specific variants see buildScene3DFrustumFromCamera in @flighthq/camera (or compute
|
|
12
|
+
// the viewProjection from getCamera3DViewProjectionMatrix4 before calling this).
|
|
13
|
+
export function buildScene3DFrustum(out, viewProjection) {
|
|
14
|
+
setFrustumFromMatrix4(out, viewProjection);
|
|
15
|
+
}
|
|
16
|
+
// Walks the subtree rooted at `root` depth-first and appends each Mesh leaf whose world-space
|
|
17
|
+
// AABB intersects `frustum` to `out`. Transform-only group nodes (no geometry) are never
|
|
18
|
+
// collected — only Mesh leaves that pass the AABB frustum test appear in the result. Disabled
|
|
19
|
+
// nodes (`enabled === false`) and their entire subtrees are skipped.
|
|
20
|
+
//
|
|
21
|
+
// `out` is not cleared before collection — the caller controls accumulation order across
|
|
22
|
+
// multiple roots. Returns `out` for convenience.
|
|
23
|
+
//
|
|
24
|
+
// Design note: the integration point with `prepareScene3DRender` is caller-driven — the caller
|
|
25
|
+
// builds the cull list here, then passes it to the render walk. Scene3D does not call render; the
|
|
26
|
+
// render walk does not call scene. This keeps the dependency graph acyclic.
|
|
27
|
+
export function cullNode3DByFrustum(out, root, frustum) {
|
|
28
|
+
_cullNode(out, root, frustum);
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
function _cullNode(out, node, frustum) {
|
|
32
|
+
if (!node.enabled)
|
|
33
|
+
return;
|
|
34
|
+
if (isMesh(node)) {
|
|
35
|
+
const geom = node.geometry;
|
|
36
|
+
let localBounds = geom.bounds;
|
|
37
|
+
if (localBounds === null) {
|
|
38
|
+
computeMeshGeometryBounds(_scratchLocalAabb, geom);
|
|
39
|
+
localBounds = _scratchLocalAabb;
|
|
40
|
+
}
|
|
41
|
+
if (localBounds.min.x <= localBounds.max.x) {
|
|
42
|
+
ensureNodeWorldMatrix4(node);
|
|
43
|
+
const worldMatrix = getNodeWorldMatrix4(node);
|
|
44
|
+
transformAabbByMatrix4(_scratchWorldAabb, localBounds, worldMatrix);
|
|
45
|
+
if (isFrustumIntersectingAabb(frustum, _scratchWorldAabb)) {
|
|
46
|
+
out.push(node);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Mesh with empty bounds contributes nothing.
|
|
50
|
+
}
|
|
51
|
+
// Transform-only group nodes have no geometry and are not collected — only Mesh leaves that
|
|
52
|
+
// pass the frustum test are appended. Descend into children regardless of node type.
|
|
53
|
+
const children = getNodeRuntime(node).children;
|
|
54
|
+
if (children !== null) {
|
|
55
|
+
for (let i = 0; i < children.length; i++) {
|
|
56
|
+
_cullNode(out, children[i], frustum);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const _scratchLocalAabb = createAabb();
|
|
61
|
+
const _scratchWorldAabb = createAabb();
|
|
62
|
+
//# sourceMappingURL=sceneNodeCulling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNodeCulling.js","sourceRoot":"","sources":["../src/sceneNodeCulling.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,yBAAyB,EACzB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG7F,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,gFAAgF;AAChF,wFAAwF;AACxF,kGAAkG;AAClG,wFAAwF;AACxF,EAAE;AACF,+FAA+F;AAC/F,iGAAiG;AACjG,iFAAiF;AACjF,MAAM,UAAU,mBAAmB,CAAC,GAAgB,EAAE,cAAqC;IACzF,qBAAqB,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;AAC7C,CAAC;AAED,8FAA8F;AAC9F,yFAAyF;AACzF,8FAA8F;AAC9F,qEAAqE;AACrE,EAAE;AACF,yFAAyF;AACzF,iDAAiD;AACjD,EAAE;AACF,+FAA+F;AAC/F,kGAAkG;AAClG,4EAA4E;AAC5E,MAAM,UAAU,mBAAmB,CAAC,GAAa,EAAE,IAAsB,EAAE,OAA8B;IACvG,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,SAAS,CAAC,GAAa,EAAE,IAAsB,EAAE,OAA8B;IACtF,IAAI,CAAC,IAAI,CAAC,OAAO;QAAE,OAAO;IAC1B,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC3B,IAAI,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC;QAC9B,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;YACzB,yBAAyB,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;YACnD,WAAW,GAAG,iBAAiB,CAAC;QAClC,CAAC;QACD,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC3C,sBAAsB,CAAC,IAAI,CAAC,CAAC;YAC7B,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;YAC9C,sBAAsB,CAAC,iBAAiB,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;YACpE,IAAI,yBAAyB,CAAC,OAAO,EAAE,iBAAiB,CAAC,EAAE,CAAC;gBAC1D,GAAG,CAAC,IAAI,CAAC,IAAc,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QACD,8CAA8C;IAChD,CAAC;IACD,4FAA4F;IAC5F,qFAAqF;IACrF,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC;IAC/C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAW,EAAE,OAAO,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,iBAAiB,GAAG,UAAU,EAAE,CAAC;AACvC,MAAM,iBAAiB,GAAG,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNodeDispose.d.ts","sourceRoot":"","sources":["../src/sceneNodeDispose.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAY9C,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEhD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { disposeNode } from '@flighthq/node';
|
|
2
|
+
// Detaches `node` from its parent (if any), recursively disposes all descendants bottom-up,
|
|
3
|
+
// clears signal/observer registries, and releases graph state so the subtree becomes eligible for
|
|
4
|
+
// garbage collection.
|
|
5
|
+
//
|
|
6
|
+
// After `disposeNode3D`, `node` must not be re-added to a graph. GPU resources (mesh geometry
|
|
7
|
+
// uploads, render proxies) are not freed here — they are non-GC resources owned by the render
|
|
8
|
+
// packages; call the appropriate `destroy*` function on the render state before or after disposing.
|
|
9
|
+
//
|
|
10
|
+
// Note: `dispose*` (detach and release to GC) vs `destroy*` (free a non-GC resource immediately).
|
|
11
|
+
// This function implements the `dispose*` contract: no GPU or native handles are released here.
|
|
12
|
+
export function disposeNode3D(node) {
|
|
13
|
+
disposeNode(node);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=sceneNodeDispose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNodeDispose.js","sourceRoot":"","sources":["../src/sceneNodeDispose.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,4FAA4F;AAC5F,kGAAkG;AAClG,sBAAsB;AACtB,EAAE;AACF,8FAA8F;AAC9F,8FAA8F;AAC9F,oGAAoG;AACpG,EAAE;AACF,kGAAkG;AAClG,gGAAgG;AAChG,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,WAAW,CAAC,IAAI,CAAC,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNodeTransform.d.ts","sourceRoot":"","sources":["../src/sceneNodeTransform.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAe3D,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,QAAQ,CAAC,WAAW,CAAC,EAC1B,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,EAC7B,EAAE,EAAE,QAAQ,CAAC,WAAW,CAAC,GACxB,IAAI,CAiDN"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createMatrix4 } from '@flighthq/geometry';
|
|
2
|
+
import { setNodeLocalMatrix4 } from '@flighthq/node';
|
|
3
|
+
// Sets the node's local matrix directly to a model-space look-at transform that places the node at
|
|
4
|
+
// `eye`, oriented so its local -Z axis points toward `target`, with the given `up` hint vector. The
|
|
5
|
+
// resulting matrix has unit scale and no shear. This is a **model** matrix (position = eye,
|
|
6
|
+
// rotation = orientation toward target); it is NOT a view matrix — use getCameraViewMatrix4 for
|
|
7
|
+
// camera view transforms. Because it authors the matrix directly, the node's position/rotation/scale
|
|
8
|
+
// fields go dormant (detached) until reattached.
|
|
9
|
+
//
|
|
10
|
+
// Read/write the node's `position`/`rotation`/`scale` fields directly for component authoring (call
|
|
11
|
+
// `invalidateNodeLocalTransform` after), or `setNodeTransform3D`/`setNodeLocalMatrix4` for a whole
|
|
12
|
+
// transform. This exists because building a look-at orientation matrix is non-trivial.
|
|
13
|
+
//
|
|
14
|
+
// Note: geometry's setMatrix4LookAt is a view matrix (inverted). This function builds the model
|
|
15
|
+
// matrix directly: basis vectors are the same but the translation is eye, not -dot(axis, eye).
|
|
16
|
+
export function setNode3DLookAt(node, eye, target, up) {
|
|
17
|
+
const eyeX = eye.x, eyeY = eye.y, eyeZ = eye.z;
|
|
18
|
+
// Z axis = normalize(eye - target) — points backward in RH; -Z is the forward direction.
|
|
19
|
+
let zx = eyeX - target.x;
|
|
20
|
+
let zy = eyeY - target.y;
|
|
21
|
+
let zz = eyeZ - target.z;
|
|
22
|
+
let zl = Math.sqrt(zx * zx + zy * zy + zz * zz);
|
|
23
|
+
if (zl === 0) {
|
|
24
|
+
zz = 1;
|
|
25
|
+
zl = 1;
|
|
26
|
+
}
|
|
27
|
+
zx /= zl;
|
|
28
|
+
zy /= zl;
|
|
29
|
+
zz /= zl;
|
|
30
|
+
// X axis = normalize(cross(up, z)).
|
|
31
|
+
let xx = up.y * zz - up.z * zy;
|
|
32
|
+
let xy = up.z * zx - up.x * zz;
|
|
33
|
+
let xz = up.x * zy - up.y * zx;
|
|
34
|
+
const xl = Math.sqrt(xx * xx + xy * xy + xz * xz);
|
|
35
|
+
if (xl !== 0) {
|
|
36
|
+
xx /= xl;
|
|
37
|
+
xy /= xl;
|
|
38
|
+
xz /= xl;
|
|
39
|
+
}
|
|
40
|
+
// Y axis = cross(z, x).
|
|
41
|
+
const yx = zy * xz - zz * xy;
|
|
42
|
+
const yy = zz * xx - zx * xz;
|
|
43
|
+
const yz = zx * xy - zy * xx;
|
|
44
|
+
// Column-major model matrix: [X|Y|Z|translation].
|
|
45
|
+
const m = _scratchMatrix.m;
|
|
46
|
+
m[0] = xx;
|
|
47
|
+
m[1] = xy;
|
|
48
|
+
m[2] = xz;
|
|
49
|
+
m[3] = 0;
|
|
50
|
+
m[4] = yx;
|
|
51
|
+
m[5] = yy;
|
|
52
|
+
m[6] = yz;
|
|
53
|
+
m[7] = 0;
|
|
54
|
+
m[8] = zx;
|
|
55
|
+
m[9] = zy;
|
|
56
|
+
m[10] = zz;
|
|
57
|
+
m[11] = 0;
|
|
58
|
+
m[12] = eyeX;
|
|
59
|
+
m[13] = eyeY;
|
|
60
|
+
m[14] = eyeZ;
|
|
61
|
+
m[15] = 1;
|
|
62
|
+
setNodeLocalMatrix4(node, _scratchMatrix);
|
|
63
|
+
}
|
|
64
|
+
const _scratchMatrix = createMatrix4();
|
|
65
|
+
//# sourceMappingURL=sceneNodeTransform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sceneNodeTransform.js","sourceRoot":"","sources":["../src/sceneNodeTransform.ts"],"names":[],"mappings":"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"}
|