@pascal-app/viewer 1.0.0-beta.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +107 -0
- package/dist/capture/asset-url.d.ts +2 -0
- package/dist/capture/asset-url.d.ts.map +1 -0
- package/dist/capture/asset-url.js +13 -0
- package/dist/capture/capture-runtime.d.ts +43 -0
- package/dist/capture/capture-runtime.d.ts.map +1 -0
- package/dist/capture/capture-runtime.js +228 -0
- package/dist/capture/frame.d.ts +4 -0
- package/dist/capture/frame.d.ts.map +1 -0
- package/dist/capture/frame.js +21 -0
- package/dist/capture/index.d.ts +12 -0
- package/dist/capture/index.d.ts.map +1 -0
- package/dist/capture/index.js +11 -0
- package/dist/capture/layer-visibility.d.ts +5 -0
- package/dist/capture/layer-visibility.d.ts.map +1 -0
- package/dist/capture/layer-visibility.js +11 -0
- package/dist/capture/layers/clay-matcap.d.ts +3 -0
- package/dist/capture/layers/clay-matcap.d.ts.map +1 -0
- package/dist/capture/layers/clay-matcap.js +26 -0
- package/dist/capture/layers/device-motion-layer.d.ts +7 -0
- package/dist/capture/layers/device-motion-layer.d.ts.map +1 -0
- package/dist/capture/layers/device-motion-layer.js +78 -0
- package/dist/capture/layers/point-cloud-layer.d.ts +15 -0
- package/dist/capture/layers/point-cloud-layer.d.ts.map +1 -0
- package/dist/capture/layers/point-cloud-layer.js +106 -0
- package/dist/capture/layers/room-model-layer.d.ts +9 -0
- package/dist/capture/layers/room-model-layer.d.ts.map +1 -0
- package/dist/capture/layers/room-model-layer.js +71 -0
- package/dist/capture/layers/surface-mesh-data.d.ts +9 -0
- package/dist/capture/layers/surface-mesh-data.d.ts.map +1 -0
- package/dist/capture/layers/surface-mesh-data.js +74 -0
- package/dist/capture/layers/surface-mesh-layer.d.ts +7 -0
- package/dist/capture/layers/surface-mesh-layer.d.ts.map +1 -0
- package/dist/capture/layers/surface-mesh-layer.js +16 -0
- package/dist/capture/preview.d.ts +3 -0
- package/dist/capture/preview.d.ts.map +1 -0
- package/dist/capture/preview.js +2 -0
- package/dist/capture/source-state.d.ts +22 -0
- package/dist/capture/source-state.d.ts.map +1 -0
- package/dist/capture/source-state.js +182 -0
- package/dist/capture/stream-rendering.d.ts +14 -0
- package/dist/capture/stream-rendering.d.ts.map +1 -0
- package/dist/capture/stream-rendering.js +69 -0
- package/dist/capture/trajectory.d.ts +20 -0
- package/dist/capture/trajectory.d.ts.map +1 -0
- package/dist/capture/trajectory.js +77 -0
- package/dist/components/viewer/batched-mesh-spike.d.ts +14 -0
- package/dist/components/viewer/batched-mesh-spike.d.ts.map +1 -0
- package/dist/components/viewer/batched-mesh-spike.js +64 -0
- package/dist/components/viewer/frame-limiter.d.ts +11 -0
- package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
- package/dist/components/viewer/frame-limiter.js +59 -18
- package/dist/components/viewer/index.d.ts +15 -0
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +74 -82
- package/dist/components/viewer/lights.d.ts.map +1 -1
- package/dist/components/viewer/lights.js +123 -89
- package/dist/components/viewer/perf-monitor.d.ts +6 -1
- package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
- package/dist/components/viewer/perf-monitor.js +306 -115
- package/dist/components/viewer/perf-panel.d.ts +3 -0
- package/dist/components/viewer/perf-panel.d.ts.map +1 -0
- package/dist/components/viewer/perf-panel.js +178 -0
- package/dist/components/viewer/pointer-raycast-layers.d.ts +15 -0
- package/dist/components/viewer/pointer-raycast-layers.d.ts.map +1 -0
- package/dist/components/viewer/pointer-raycast-layers.js +28 -0
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +124 -83
- package/dist/components/viewer/registered-systems.d.ts +14 -5
- package/dist/components/viewer/registered-systems.d.ts.map +1 -1
- package/dist/components/viewer/registered-systems.js +22 -10
- package/dist/components/viewer/scene-atmosphere.d.ts +30 -0
- package/dist/components/viewer/scene-atmosphere.d.ts.map +1 -0
- package/dist/components/viewer/scene-atmosphere.js +89 -0
- package/dist/components/viewer/scene-environment.d.ts.map +1 -1
- package/dist/components/viewer/scene-environment.js +19 -5
- package/dist/components/viewer/scene-ground-replacement.d.ts +5 -0
- package/dist/components/viewer/scene-ground-replacement.d.ts.map +1 -0
- package/dist/components/viewer/scene-ground-replacement.js +35 -0
- package/dist/components/viewer/selection-manager.d.ts.map +1 -1
- package/dist/components/viewer/selection-manager.js +7 -2
- package/dist/components/viewer/unsupported-gpu-fallback.d.ts +2 -0
- package/dist/components/viewer/unsupported-gpu-fallback.d.ts.map +1 -0
- package/dist/components/viewer/unsupported-gpu-fallback.js +4 -0
- package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
- package/dist/components/viewer/viewer-camera.js +4 -1
- package/dist/components/viewer/viewer-presentations.d.ts +67 -0
- package/dist/components/viewer/viewer-presentations.d.ts.map +1 -0
- package/dist/components/viewer/viewer-presentations.js +120 -0
- package/dist/hooks/use-library-materials-version.d.ts +7 -0
- package/dist/hooks/use-library-materials-version.d.ts.map +1 -0
- package/dist/hooks/use-library-materials-version.js +10 -0
- package/dist/hooks/use-node-events.d.ts.map +1 -1
- package/dist/hooks/use-node-events.js +1 -0
- package/dist/index.d.ts +20 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -7
- package/dist/lib/csg-utils.d.ts +1 -0
- package/dist/lib/csg-utils.d.ts.map +1 -1
- package/dist/lib/csg-utils.js +6 -1
- package/dist/lib/dispose-object3d.d.ts +4 -0
- package/dist/lib/dispose-object3d.d.ts.map +1 -0
- package/dist/lib/dispose-object3d.js +27 -0
- package/dist/lib/geometry-groups.d.ts +17 -0
- package/dist/lib/geometry-groups.d.ts.map +1 -0
- package/dist/lib/geometry-groups.js +53 -0
- package/dist/lib/gpu-perf.d.ts +0 -2
- package/dist/lib/gpu-perf.d.ts.map +1 -1
- package/dist/lib/gpu-perf.js +7 -21
- package/dist/lib/isolation.d.ts +8 -8
- package/dist/lib/isolation.d.ts.map +1 -1
- package/dist/lib/isolation.js +18 -30
- package/dist/lib/layer-pass.d.ts +28 -0
- package/dist/lib/layer-pass.d.ts.map +1 -0
- package/dist/lib/layer-pass.js +254 -0
- package/dist/lib/layers.d.ts +16 -0
- package/dist/lib/layers.d.ts.map +1 -1
- package/dist/lib/layers.js +18 -0
- package/dist/lib/materials.d.ts +12 -0
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +51 -17
- package/dist/lib/merged-outline-node.d.ts +17 -8
- package/dist/lib/merged-outline-node.d.ts.map +1 -1
- package/dist/lib/merged-outline-node.js +194 -52
- package/dist/lib/perf-actions.d.ts +55 -0
- package/dist/lib/perf-actions.d.ts.map +1 -0
- package/dist/lib/perf-actions.js +211 -0
- package/dist/lib/perf-observers.d.ts +2 -0
- package/dist/lib/perf-observers.d.ts.map +1 -0
- package/dist/lib/perf-observers.js +17 -0
- package/dist/lib/perf-panel-store.d.ts +71 -0
- package/dist/lib/perf-panel-store.d.ts.map +1 -0
- package/dist/lib/perf-panel-store.js +29 -0
- package/dist/lib/perf-tracks.d.ts +43 -0
- package/dist/lib/perf-tracks.d.ts.map +1 -0
- package/dist/lib/perf-tracks.js +113 -0
- package/dist/lib/pointer-events.d.ts +7 -0
- package/dist/lib/pointer-events.d.ts.map +1 -0
- package/dist/lib/pointer-events.js +680 -0
- package/dist/lib/post-processing-resources.d.ts +12 -0
- package/dist/lib/post-processing-resources.d.ts.map +1 -0
- package/dist/lib/post-processing-resources.js +19 -0
- package/dist/lib/renderer-capability.d.ts +56 -0
- package/dist/lib/renderer-capability.d.ts.map +1 -0
- package/dist/lib/renderer-capability.js +116 -0
- package/dist/lib/scene-visibility.d.ts +15 -0
- package/dist/lib/scene-visibility.d.ts.map +1 -0
- package/dist/lib/scene-visibility.js +69 -0
- package/dist/lib/shadow-only.d.ts +16 -0
- package/dist/lib/shadow-only.d.ts.map +1 -1
- package/dist/lib/shadow-only.js +8 -17
- package/dist/lib/snapshot-pipeline.d.ts +9 -0
- package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
- package/dist/lib/snapshot-pipeline.js +33 -9
- package/dist/store/use-viewer.d.ts +7 -6
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/systems/ceiling/ceiling-system.js +1 -1
- package/dist/systems/door/door-animation-system.d.ts.map +1 -1
- package/dist/systems/door/door-animation-system.js +6 -9
- package/dist/systems/door/door-system.d.ts.map +1 -1
- package/dist/systems/door/door-system.js +13 -2
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -1
- package/dist/systems/floor-elevation/floor-elevation-system.js +9 -0
- package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
- package/dist/systems/geometry/geometry-system.js +5 -28
- package/dist/systems/level/level-system.d.ts.map +1 -1
- package/dist/systems/level/level-system.js +8 -2
- package/dist/systems/level/level-utils.d.ts +9 -0
- package/dist/systems/level/level-utils.d.ts.map +1 -1
- package/dist/systems/level/level-utils.js +14 -0
- package/dist/systems/perf-action-settle/perf-action-settle-system.d.ts +8 -0
- package/dist/systems/perf-action-settle/perf-action-settle-system.d.ts.map +1 -0
- package/dist/systems/perf-action-settle/perf-action-settle-system.js +32 -0
- package/dist/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +1196 -58
- package/dist/systems/scan/scan-system.js +6 -5
- package/dist/systems/slab/slab-system.d.ts.map +1 -1
- package/dist/systems/slab/slab-system.js +1 -2
- package/dist/systems/stair/stair-system.d.ts.map +1 -1
- package/dist/systems/stair/stair-system.js +9 -8
- package/dist/systems/surface-hole-geometry.d.ts +1 -1
- package/dist/systems/surface-hole-geometry.d.ts.map +1 -1
- package/dist/systems/surface-hole-geometry.js +1 -1
- package/dist/systems/wall/level-miter-cache.d.ts +10 -0
- package/dist/systems/wall/level-miter-cache.d.ts.map +1 -0
- package/dist/systems/wall/level-miter-cache.js +40 -0
- package/dist/systems/wall/wall-build-lifecycle.d.ts +9 -0
- package/dist/systems/wall/wall-build-lifecycle.d.ts.map +1 -0
- package/dist/systems/wall/wall-build-lifecycle.js +74 -0
- package/dist/systems/wall/wall-cutout-cache.d.ts +57 -0
- package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -0
- package/dist/systems/wall/wall-cutout-cache.js +304 -0
- package/dist/systems/wall/wall-cutout.d.ts +24 -1
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +33 -140
- package/dist/systems/wall/wall-material-variant.d.ts +31 -0
- package/dist/systems/wall/wall-material-variant.d.ts.map +1 -0
- package/dist/systems/wall/wall-material-variant.js +10 -0
- package/dist/systems/wall/wall-materials.d.ts +6 -0
- package/dist/systems/wall/wall-materials.d.ts.map +1 -1
- package/dist/systems/wall/wall-materials.js +29 -13
- package/dist/systems/wall/wall-placeholder-sweep.d.ts +50 -0
- package/dist/systems/wall/wall-placeholder-sweep.d.ts.map +1 -0
- package/dist/systems/wall/wall-placeholder-sweep.js +51 -0
- package/dist/systems/wall/wall-rebuild-notifications.d.ts +5 -0
- package/dist/systems/wall/wall-rebuild-notifications.d.ts.map +1 -0
- package/dist/systems/wall/wall-rebuild-notifications.js +23 -0
- package/dist/systems/wall/wall-system.d.ts +13 -2
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +413 -148
- package/dist/systems/window/window-animation-system.d.ts.map +1 -1
- package/dist/systems/window/window-animation-system.js +9 -8
- package/dist/systems/window/window-system.d.ts +1 -0
- package/dist/systems/window/window-system.d.ts.map +1 -1
- package/dist/systems/window/window-system.js +16 -2
- package/package.json +18 -3
- package/dist/components/viewer/scene-bvh.test.d.ts +0 -2
- package/dist/components/viewer/scene-bvh.test.d.ts.map +0 -1
- package/dist/components/viewer/scene-bvh.test.js +0 -13
- package/dist/lib/csg-utils.test.d.ts +0 -2
- package/dist/lib/csg-utils.test.d.ts.map +0 -1
- package/dist/lib/csg-utils.test.js +0 -45
- package/dist/lib/materials.test.d.ts +0 -2
- package/dist/lib/materials.test.d.ts.map +0 -1
- package/dist/lib/materials.test.js +0 -25
- package/dist/lib/merged-outline-node.test.d.ts +0 -2
- package/dist/lib/merged-outline-node.test.d.ts.map +0 -1
- package/dist/lib/merged-outline-node.test.js +0 -22
- package/dist/lib/polygon-union.d.ts +0 -4
- package/dist/lib/polygon-union.d.ts.map +0 -1
- package/dist/lib/polygon-union.js +0 -289
- package/dist/lib/polygon-union.test.d.ts +0 -2
- package/dist/lib/polygon-union.test.d.ts.map +0 -1
- package/dist/lib/polygon-union.test.js +0 -105
- package/dist/lib/texture-reference.test.d.ts +0 -2
- package/dist/lib/texture-reference.test.d.ts.map +0 -1
- package/dist/lib/texture-reference.test.js +0 -86
- package/dist/store/use-viewer.test.d.ts +0 -2
- package/dist/store/use-viewer.test.d.ts.map +0 -1
- package/dist/store/use-viewer.test.js +0 -61
- package/dist/systems/door/door-animation.test.d.ts +0 -2
- package/dist/systems/door/door-animation.test.d.ts.map +0 -1
- package/dist/systems/door/door-animation.test.js +0 -51
- package/dist/systems/door/door-floor-alignment.test.d.ts +0 -2
- package/dist/systems/door/door-floor-alignment.test.d.ts.map +0 -1
- package/dist/systems/door/door-floor-alignment.test.js +0 -50
- package/dist/systems/geometry/geometry-system.test.d.ts +0 -2
- package/dist/systems/geometry/geometry-system.test.d.ts.map +0 -1
- package/dist/systems/geometry/geometry-system.test.js +0 -30
- package/dist/systems/slab/slab-system.test.d.ts +0 -2
- package/dist/systems/slab/slab-system.test.d.ts.map +0 -1
- package/dist/systems/slab/slab-system.test.js +0 -102
- package/dist/systems/wall/opening-cutout-geometry.test.d.ts +0 -2
- package/dist/systems/wall/opening-cutout-geometry.test.d.ts.map +0 -1
- package/dist/systems/wall/opening-cutout-geometry.test.js +0 -172
- package/dist/systems/wall/wall-opening-cutout.test.d.ts +0 -2
- package/dist/systems/wall/wall-opening-cutout.test.d.ts.map +0 -1
- package/dist/systems/wall/wall-opening-cutout.test.js +0 -59
- package/dist/systems/wall/wall-support-extension.test.d.ts +0 -2
- package/dist/systems/wall/wall-support-extension.test.d.ts.map +0 -1
- package/dist/systems/wall/wall-support-extension.test.js +0 -116
- package/dist/systems/wall/wall-terrain-bottom.test.d.ts +0 -2
- package/dist/systems/wall/wall-terrain-bottom.test.d.ts.map +0 -1
- package/dist/systems/wall/wall-terrain-bottom.test.js +0 -34
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// Only one index may observe a scene, and observed objects must own their Layers.
|
|
2
|
+
// Insertions without childadded are not observed: call register(subtree) afterward.
|
|
3
|
+
// Replaced Layers are repaired for known members during prepare(); other objects
|
|
4
|
+
// need register(object), since discovering them would require a full-scene scan.
|
|
5
|
+
import { Object3D, Vector2 } from 'three';
|
|
6
|
+
import { PassNode } from 'three/webgpu';
|
|
7
|
+
const maskObserver = Symbol('LayerPassIndex.maskObserver');
|
|
8
|
+
function maskOwner(object) {
|
|
9
|
+
const get = Object.getOwnPropertyDescriptor(object.layers, 'mask')?.get;
|
|
10
|
+
return get?.[maskObserver];
|
|
11
|
+
}
|
|
12
|
+
// Observe mask writes as well as child events: R3F's numeric `layers` prop calls
|
|
13
|
+
// Layers.set(), while imperative producers also use enable() and direct masks.
|
|
14
|
+
// Nothing on Object3D/Layers.prototype is patched, and detach restores the field.
|
|
15
|
+
export class LayerPassIndex {
|
|
16
|
+
source;
|
|
17
|
+
members = new Map();
|
|
18
|
+
cleanups = new Map();
|
|
19
|
+
constructor(source, layers) {
|
|
20
|
+
this.source = source;
|
|
21
|
+
for (const layer of layers)
|
|
22
|
+
this.members.set(1 << layer, new Set());
|
|
23
|
+
try {
|
|
24
|
+
this.attach(source);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
this.dispose();
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
register(subtree) {
|
|
32
|
+
this.detach(subtree);
|
|
33
|
+
for (let object = subtree; object; object = object.parent) {
|
|
34
|
+
if (object === this.source) {
|
|
35
|
+
this.attach(subtree);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
attach = (object) => {
|
|
41
|
+
if (this.cleanups.has(object))
|
|
42
|
+
return;
|
|
43
|
+
const layers = object.layers;
|
|
44
|
+
if (maskOwner(object)) {
|
|
45
|
+
throw new Error('LayerPassIndex requires one index per scene and unshared Layers');
|
|
46
|
+
}
|
|
47
|
+
let mask = layers.mask;
|
|
48
|
+
const sync = () => {
|
|
49
|
+
for (const [bit, members] of this.members) {
|
|
50
|
+
if ((mask & bit) !== 0 && object !== this.source)
|
|
51
|
+
members.add(object);
|
|
52
|
+
else
|
|
53
|
+
members.delete(object);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const getMask = Object.assign(() => mask, { [maskObserver]: object });
|
|
57
|
+
Object.defineProperty(layers, 'mask', {
|
|
58
|
+
configurable: true,
|
|
59
|
+
enumerable: true,
|
|
60
|
+
get: getMask,
|
|
61
|
+
set: (value) => {
|
|
62
|
+
if (mask === value)
|
|
63
|
+
return;
|
|
64
|
+
mask = value;
|
|
65
|
+
sync();
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
const added = ({ child }) => this.attach(child);
|
|
69
|
+
const removed = ({ child }) => this.detach(child);
|
|
70
|
+
object.addEventListener('childadded', added);
|
|
71
|
+
object.addEventListener('childremoved', removed);
|
|
72
|
+
this.cleanups.set(object, () => {
|
|
73
|
+
object.removeEventListener('childadded', added);
|
|
74
|
+
object.removeEventListener('childremoved', removed);
|
|
75
|
+
if (Object.getOwnPropertyDescriptor(layers, 'mask')?.get === getMask) {
|
|
76
|
+
Object.defineProperty(layers, 'mask', {
|
|
77
|
+
configurable: true,
|
|
78
|
+
enumerable: true,
|
|
79
|
+
writable: true,
|
|
80
|
+
value: mask,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
for (const members of this.members.values())
|
|
84
|
+
members.delete(object);
|
|
85
|
+
});
|
|
86
|
+
sync();
|
|
87
|
+
for (const child of object.children)
|
|
88
|
+
this.attach(child);
|
|
89
|
+
};
|
|
90
|
+
detach(object) {
|
|
91
|
+
for (const child of object.children)
|
|
92
|
+
this.detach(child);
|
|
93
|
+
this.cleanups.get(object)?.();
|
|
94
|
+
this.cleanups.delete(object);
|
|
95
|
+
}
|
|
96
|
+
prepare(layer, roots) {
|
|
97
|
+
roots.length = 0;
|
|
98
|
+
const members = this.members.get(1 << layer);
|
|
99
|
+
// Repairs can change membership, so finish them before choosing nested roots.
|
|
100
|
+
for (const tracked of this.members.values()) {
|
|
101
|
+
for (const object of [...tracked]) {
|
|
102
|
+
let root = object;
|
|
103
|
+
while (root.parent && root !== this.source)
|
|
104
|
+
root = root.parent;
|
|
105
|
+
if (root !== this.source)
|
|
106
|
+
this.detach(root);
|
|
107
|
+
else if (maskOwner(object) !== object)
|
|
108
|
+
this.register(object);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
let drawable = false;
|
|
112
|
+
let shadowLight = false;
|
|
113
|
+
for (const object of members) {
|
|
114
|
+
let visible = object.visible;
|
|
115
|
+
let nested = false;
|
|
116
|
+
for (let parent = object.parent; parent; parent = parent.parent) {
|
|
117
|
+
if (!parent.visible)
|
|
118
|
+
visible = false;
|
|
119
|
+
if (members.has(parent))
|
|
120
|
+
nested = true;
|
|
121
|
+
}
|
|
122
|
+
if (!visible)
|
|
123
|
+
continue;
|
|
124
|
+
const { material, isLight, castShadow } = object;
|
|
125
|
+
if (material) {
|
|
126
|
+
drawable ||= Array.isArray(material) ? material.some((m) => m.visible) : material.visible;
|
|
127
|
+
}
|
|
128
|
+
shadowLight ||= isLight === true && castShadow;
|
|
129
|
+
if (!nested)
|
|
130
|
+
roots.push(object);
|
|
131
|
+
}
|
|
132
|
+
// Keep source traversal order even when a producer switches layers after
|
|
133
|
+
// mounting. Ancestors on this layer remain intact, retaining group order,
|
|
134
|
+
// clipping and LOD behavior; layers do not inherit through other ancestors.
|
|
135
|
+
roots.sort(compareSceneOrder);
|
|
136
|
+
return { drawable, shadowLight };
|
|
137
|
+
}
|
|
138
|
+
dispose() {
|
|
139
|
+
for (const cleanup of this.cleanups.values())
|
|
140
|
+
cleanup();
|
|
141
|
+
this.cleanups.clear();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function compareSceneOrder(a, b) {
|
|
145
|
+
const pathA = [];
|
|
146
|
+
const pathB = [];
|
|
147
|
+
for (let object = a; object; object = object.parent)
|
|
148
|
+
pathA.push(object);
|
|
149
|
+
for (let object = b; object; object = object.parent)
|
|
150
|
+
pathB.push(object);
|
|
151
|
+
let i = pathA.length - 1;
|
|
152
|
+
let j = pathB.length - 1;
|
|
153
|
+
while (i >= 0 && j >= 0 && pathA[i] === pathB[j]) {
|
|
154
|
+
i--;
|
|
155
|
+
j--;
|
|
156
|
+
}
|
|
157
|
+
const siblings = pathA[i + 1].children;
|
|
158
|
+
return siblings.indexOf(pathA[i]) - siblings.indexOf(pathB[j]);
|
|
159
|
+
}
|
|
160
|
+
export class LayerPassNode extends PassNode {
|
|
161
|
+
index;
|
|
162
|
+
layer;
|
|
163
|
+
mainPass;
|
|
164
|
+
roots = [];
|
|
165
|
+
size = new Vector2();
|
|
166
|
+
needsClear = true;
|
|
167
|
+
constructor(index, camera, layer, mainPass) {
|
|
168
|
+
super(PassNode.COLOR, index.source, camera);
|
|
169
|
+
this.index = index;
|
|
170
|
+
this.layer = layer;
|
|
171
|
+
this.mainPass = mainPass;
|
|
172
|
+
// A scene view, not cloned meshes: callbacks, environment, fog, materials,
|
|
173
|
+
// skeletons and world matrices retain their original owners and values.
|
|
174
|
+
this.scene = new Proxy(index.source, {
|
|
175
|
+
get: (source, key) => {
|
|
176
|
+
if (key === 'children')
|
|
177
|
+
return this.roots;
|
|
178
|
+
if (key === 'matrixWorldAutoUpdate')
|
|
179
|
+
return false;
|
|
180
|
+
return Reflect.get(source, key, source);
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
dispose() {
|
|
185
|
+
this.roots.length = 0;
|
|
186
|
+
super.dispose();
|
|
187
|
+
}
|
|
188
|
+
updateBefore(frame) {
|
|
189
|
+
// NodeFrame deduplicates FRAME updates. Make the dependency explicit rather
|
|
190
|
+
// than relying on which composite expression the TSL builder visits first.
|
|
191
|
+
frame.updateBeforeNode(this.mainPass);
|
|
192
|
+
const { drawable, shadowLight } = this.index.prepare(this.layer, this.roots);
|
|
193
|
+
const renderer = frame.renderer;
|
|
194
|
+
const source = this.index.source;
|
|
195
|
+
const hasBackground = source.background !== null || ('backgroundNode' in source && source.backgroundNode != null);
|
|
196
|
+
const hasSceneCallbacks = source.onBeforeRender !== Object3D.prototype.onBeforeRender ||
|
|
197
|
+
source.onAfterRender !== Object3D.prototype.onAfterRender;
|
|
198
|
+
if (drawable || hasBackground || hasSceneCallbacks) {
|
|
199
|
+
this.needsClear = true;
|
|
200
|
+
// Shadows need all source casters; custom callbacks need the original
|
|
201
|
+
// scene receiver and graph, including when they enable an empty layer.
|
|
202
|
+
const root = this.scene;
|
|
203
|
+
if (shadowLight || hasSceneCallbacks)
|
|
204
|
+
this.scene = source;
|
|
205
|
+
try {
|
|
206
|
+
if (this.scene !== source) {
|
|
207
|
+
const updatedAncestors = new Set();
|
|
208
|
+
const updateAncestor = (object) => {
|
|
209
|
+
if (!object || updatedAncestors.has(object))
|
|
210
|
+
return;
|
|
211
|
+
updateAncestor(object.parent);
|
|
212
|
+
// Force world refreshes even when a manual local matrix is clean.
|
|
213
|
+
object.matrixWorldNeedsUpdate = true;
|
|
214
|
+
object.updateWorldMatrix(false, false);
|
|
215
|
+
updatedAncestors.add(object);
|
|
216
|
+
};
|
|
217
|
+
for (const root of this.roots) {
|
|
218
|
+
updateAncestor(root.parent);
|
|
219
|
+
root.updateMatrixWorld(true);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
super.updateBefore(frame);
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
this.scene = root;
|
|
226
|
+
}
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const outputTarget = renderer.getOutputRenderTarget();
|
|
230
|
+
if (outputTarget && 'isXRRenderTarget' in outputTarget && outputTarget.isXRRenderTarget)
|
|
231
|
+
this.size.set(outputTarget.width, outputTarget.height);
|
|
232
|
+
else
|
|
233
|
+
renderer.getDrawingBufferSize(this.size);
|
|
234
|
+
const width = this.renderTarget.width;
|
|
235
|
+
const height = this.renderTarget.height;
|
|
236
|
+
this.setSize(this.size.x, this.size.y);
|
|
237
|
+
if (width !== this.renderTarget.width || height !== this.renderTarget.height)
|
|
238
|
+
this.needsClear = true;
|
|
239
|
+
if (!this.needsClear)
|
|
240
|
+
return;
|
|
241
|
+
const target = renderer.getRenderTarget();
|
|
242
|
+
const mrt = renderer.getMRT();
|
|
243
|
+
try {
|
|
244
|
+
renderer.setRenderTarget(this.renderTarget);
|
|
245
|
+
renderer.setMRT(null);
|
|
246
|
+
renderer.clear(true, true, true);
|
|
247
|
+
this.needsClear = false;
|
|
248
|
+
}
|
|
249
|
+
finally {
|
|
250
|
+
renderer.setRenderTarget(target);
|
|
251
|
+
renderer.setMRT(mrt);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
package/dist/lib/layers.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Layers } from 'three';
|
|
1
2
|
/** Default Three.js layer for main scene geometry. */
|
|
2
3
|
export declare const SCENE_LAYER = 0;
|
|
3
4
|
/**
|
|
@@ -30,4 +31,19 @@ export declare const GRID_LAYER = 3;
|
|
|
30
31
|
* cascade) via `applyShadowOnly` / `clearShadowOnly` in `lib/shadow-only.ts`.
|
|
31
32
|
*/
|
|
32
33
|
export declare const SHADOW_ONLY_LAYER = 4;
|
|
34
|
+
/**
|
|
35
|
+
* Layer for source geometry that a collective batch already draws. No camera
|
|
36
|
+
* or pass enables it, so a batched object costs no draw call while its children
|
|
37
|
+
* and interaction proxies remain in the graph.
|
|
38
|
+
*
|
|
39
|
+
* Raycasters that query real surfaces must opt in via
|
|
40
|
+
* {@link setSurfaceRaycastLayers}, otherwise a sewn wall would stop answering
|
|
41
|
+
* measurement rays.
|
|
42
|
+
*/
|
|
43
|
+
export declare const BATCHED_LAYER = 5;
|
|
44
|
+
/**
|
|
45
|
+
* Aims a raycaster at every real scene surface, whether a wall still draws
|
|
46
|
+
* itself or a level batch draws it for us.
|
|
47
|
+
*/
|
|
48
|
+
export declare function setSurfaceRaycastLayers(layers: Layers): void;
|
|
33
49
|
//# sourceMappingURL=layers.d.ts.map
|
package/dist/lib/layers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layers.d.ts","sourceRoot":"","sources":["../../src/lib/layers.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,eAAO,MAAM,WAAW,IAAI,CAAA;AAE5B;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,IAAI,CAAA;AAE9B,oEAAoE;AACpE,eAAO,MAAM,UAAU,IAAI,CAAA;AAE3B;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,IAAI,CAAA;AAE3B;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAA"}
|
|
1
|
+
{"version":3,"file":"layers.d.ts","sourceRoot":"","sources":["../../src/lib/layers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAEnC,sDAAsD;AACtD,eAAO,MAAM,WAAW,IAAI,CAAA;AAE5B;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,IAAI,CAAA;AAE9B,oEAAoE;AACpE,eAAO,MAAM,UAAU,IAAI,CAAA;AAE3B;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,IAAI,CAAA;AAE3B;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAA;AAElC;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,IAAI,CAAA;AAE9B;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAG5D"}
|
package/dist/lib/layers.js
CHANGED
|
@@ -30,3 +30,21 @@ export const GRID_LAYER = 3;
|
|
|
30
30
|
* cascade) via `applyShadowOnly` / `clearShadowOnly` in `lib/shadow-only.ts`.
|
|
31
31
|
*/
|
|
32
32
|
export const SHADOW_ONLY_LAYER = 4;
|
|
33
|
+
/**
|
|
34
|
+
* Layer for source geometry that a collective batch already draws. No camera
|
|
35
|
+
* or pass enables it, so a batched object costs no draw call while its children
|
|
36
|
+
* and interaction proxies remain in the graph.
|
|
37
|
+
*
|
|
38
|
+
* Raycasters that query real surfaces must opt in via
|
|
39
|
+
* {@link setSurfaceRaycastLayers}, otherwise a sewn wall would stop answering
|
|
40
|
+
* measurement rays.
|
|
41
|
+
*/
|
|
42
|
+
export const BATCHED_LAYER = 5;
|
|
43
|
+
/**
|
|
44
|
+
* Aims a raycaster at every real scene surface, whether a wall still draws
|
|
45
|
+
* itself or a level batch draws it for us.
|
|
46
|
+
*/
|
|
47
|
+
export function setSurfaceRaycastLayers(layers) {
|
|
48
|
+
layers.set(SCENE_LAYER);
|
|
49
|
+
layers.enable(BATCHED_LAYER);
|
|
50
|
+
}
|
package/dist/lib/materials.d.ts
CHANGED
|
@@ -10,12 +10,21 @@ export declare const BLUEPRINT_PALETTE: Record<SurfaceRole, string>;
|
|
|
10
10
|
export declare const PRESET_PALETTES: Record<ColorPreset, Record<SurfaceRole, string>>;
|
|
11
11
|
export declare function resolveSurfaceColor(role: SurfaceRole, preset: ColorPreset, sceneThemeId?: string): string;
|
|
12
12
|
export declare const glassMaterial: MeshLambertNodeMaterial;
|
|
13
|
+
export declare function getMaterialTextureVersion(): number;
|
|
13
14
|
export declare function resolveTextureRepeat(repeat: unknown, scale: unknown): [number, number];
|
|
14
15
|
export declare function getTextureKey(material?: MaterialSchema): string;
|
|
15
16
|
export declare function applyMaterialPresetToMaterials(materialInput: THREE.Material | THREE.Material[], preset: MaterialPresetPayload | null | undefined): void;
|
|
16
17
|
export declare function createMaterialFromPreset(preset: MaterialPresetPayload, shading?: RenderShading): THREE.Material;
|
|
17
18
|
export declare function createMaterialFromPresetRef(materialPreset?: string, shading?: RenderShading): THREE.Material | null;
|
|
18
19
|
export declare function createMaterial(material?: MaterialSchema, shading?: RenderShading): THREE.Material;
|
|
20
|
+
/**
|
|
21
|
+
* Cache-signature fragment for a catalog preset ref. Dynamic library
|
|
22
|
+
* materials (AI-generated `library:mtl_*`) register asynchronously, so a ref
|
|
23
|
+
* that fails to resolve is NOT static content: tag it so signature-keyed
|
|
24
|
+
* material caches re-resolve once the library registers instead of pinning
|
|
25
|
+
* the dangling-ref fallback for the whole session.
|
|
26
|
+
*/
|
|
27
|
+
export declare function materialPresetRefSignature(ref: string): string;
|
|
19
28
|
/**
|
|
20
29
|
* Resolve a MaterialRef ('library:<id>' | 'scene:<id>') to a three.js material.
|
|
21
30
|
* Returns null for an unknown / dangling ref so callers fall back to the
|
|
@@ -41,5 +50,8 @@ export declare function DEFAULT_ROOF_MATERIAL(shading?: RenderShading): THREE.Ma
|
|
|
41
50
|
export declare function DEFAULT_SHELF_MATERIAL(shading?: RenderShading): THREE.Material;
|
|
42
51
|
export declare function DEFAULT_STAIR_MATERIAL(shading?: RenderShading): THREE.Material;
|
|
43
52
|
export declare function disposeMaterial(material: THREE.Material): void;
|
|
53
|
+
type MaterialCacheCleanup = (() => void) | (() => () => void);
|
|
54
|
+
export declare function registerMaterialCacheCleanup(cleanup: MaterialCacheCleanup): () => void;
|
|
44
55
|
export declare function clearMaterialCache(): void;
|
|
56
|
+
export {};
|
|
45
57
|
//# sourceMappingURL=materials.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../src/lib/materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,qBAAqB,EAE1B,KAAK,cAAc,EAGnB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,WAAW,EACjB,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../src/lib/materials.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/materials.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getMaterialPresetByRef, parseMaterialRef, resolveMaterial, } from '@pascal-app/core';
|
|
2
|
+
import { addAfterEffect, invalidate } from '@react-three/fiber';
|
|
2
3
|
import * as THREE from 'three';
|
|
3
4
|
import { float, mix, positionViewDirection, transformedNormalView } from 'three/tsl';
|
|
4
5
|
import { MeshLambertNodeMaterial, MeshStandardNodeMaterial } from 'three/webgpu';
|
|
@@ -82,6 +83,11 @@ const surfaceRoleMaterialCache = new Map();
|
|
|
82
83
|
const textureCache = new Map();
|
|
83
84
|
const textureLoadPromises = new Map();
|
|
84
85
|
const textureLoader = new THREE.TextureLoader();
|
|
86
|
+
let materialTextureVersion = 0;
|
|
87
|
+
// Highlight clones can observe late assignments without polling every material.
|
|
88
|
+
export function getMaterialTextureVersion() {
|
|
89
|
+
return materialTextureVersion;
|
|
90
|
+
}
|
|
85
91
|
// `.ktx2` finish maps transcode through the shared KTX2 loader (support is
|
|
86
92
|
// detected once at viewer init); everything else loads as a normal image.
|
|
87
93
|
function pickTextureLoader(url) {
|
|
@@ -276,6 +282,7 @@ function queueTextureAssignment(material, slot, path, props) {
|
|
|
276
282
|
// and crash in TextureNode.update ("null (reading 'matrix')").
|
|
277
283
|
textureMaterial[slot] = null;
|
|
278
284
|
material.needsUpdate = true;
|
|
285
|
+
materialTextureVersion++;
|
|
279
286
|
}
|
|
280
287
|
return;
|
|
281
288
|
}
|
|
@@ -289,6 +296,7 @@ function queueTextureAssignment(material, slot, path, props) {
|
|
|
289
296
|
if (cached) {
|
|
290
297
|
textureMaterial[slot] = createAssignedTexture(cached, props, slot);
|
|
291
298
|
material.needsUpdate = true;
|
|
299
|
+
materialTextureVersion++;
|
|
292
300
|
return;
|
|
293
301
|
}
|
|
294
302
|
// Cold load: clear the slot for the fetch window, and rebuild the node
|
|
@@ -298,12 +306,14 @@ function queueTextureAssignment(material, slot, path, props) {
|
|
|
298
306
|
if (textureMaterial[slot] != null) {
|
|
299
307
|
textureMaterial[slot] = null;
|
|
300
308
|
material.needsUpdate = true;
|
|
309
|
+
materialTextureVersion++;
|
|
301
310
|
}
|
|
302
311
|
loadPresetTexture(path, props, slot).then((texture) => {
|
|
303
312
|
if (!texture)
|
|
304
313
|
return;
|
|
305
314
|
textureMaterial[slot] = createAssignedTexture(texture, props, slot);
|
|
306
315
|
material.needsUpdate = true;
|
|
316
|
+
materialTextureVersion++;
|
|
307
317
|
});
|
|
308
318
|
}
|
|
309
319
|
function applyMaterialMapProperties(material, mapProperties) {
|
|
@@ -428,6 +438,16 @@ export function createMaterial(material, shading = 'rendered') {
|
|
|
428
438
|
materialCache.set(cacheKey, threeMaterial);
|
|
429
439
|
return threeMaterial;
|
|
430
440
|
}
|
|
441
|
+
/**
|
|
442
|
+
* Cache-signature fragment for a catalog preset ref. Dynamic library
|
|
443
|
+
* materials (AI-generated `library:mtl_*`) register asynchronously, so a ref
|
|
444
|
+
* that fails to resolve is NOT static content: tag it so signature-keyed
|
|
445
|
+
* material caches re-resolve once the library registers instead of pinning
|
|
446
|
+
* the dangling-ref fallback for the whole session.
|
|
447
|
+
*/
|
|
448
|
+
export function materialPresetRefSignature(ref) {
|
|
449
|
+
return getMaterialPresetByRef(ref) ? ref : `${ref}#unresolved`;
|
|
450
|
+
}
|
|
431
451
|
/**
|
|
432
452
|
* Resolve a MaterialRef ('library:<id>' | 'scene:<id>') to a three.js material.
|
|
433
453
|
* Returns null for an unknown / dangling ref so callers fall back to the
|
|
@@ -453,9 +473,9 @@ export function resolveMaterialRef(ref, sceneMaterials, shading = 'rendered') {
|
|
|
453
473
|
export function resolveSlotDefaultMaterial(slotDefault, shading = 'rendered', roughness = 0.9) {
|
|
454
474
|
if (parseMaterialRef(slotDefault)?.kind === 'library') {
|
|
455
475
|
return (createMaterialFromPresetRef(slotDefault, shading) ??
|
|
456
|
-
|
|
476
|
+
cachedDefaultMaterial(`slot-#ffffff-${roughness}`, '#ffffff', roughness, shading));
|
|
457
477
|
}
|
|
458
|
-
return
|
|
478
|
+
return cachedDefaultMaterial(`slot-${slotDefault}-${roughness}`, slotDefault, roughness, shading);
|
|
459
479
|
}
|
|
460
480
|
export function createDefaultMaterial(color = '#ffffff', roughness = 0.9, shading = 'rendered', side = THREE.FrontSide) {
|
|
461
481
|
const resolvedSide = resolveNodeMaterialSide(side);
|
|
@@ -487,9 +507,7 @@ export function createSurfaceRoleMaterial(role, preset, side = THREE.FrontSide,
|
|
|
487
507
|
// on `glassMaterial` above — the validator rejects the back-face variant
|
|
488
508
|
// for missing MRT outputs and poisons the render context (manifests as
|
|
489
509
|
// "Color target has no corresponding fragment stage output" on scene
|
|
490
|
-
// open
|
|
491
|
-
// on both gable faces on the first frame). Callers that need both sides
|
|
492
|
-
// visible (e.g. dormer back gable) must rotate the host mesh 180° so the
|
|
510
|
+
// open). Callers that need both sides visible must rotate the host mesh 180° so the
|
|
493
511
|
// FrontSide faces the viewer.
|
|
494
512
|
const resolvedSide = role === 'glazing' ? THREE.FrontSide : resolveNodeMaterialSide(side ?? THREE.FrontSide);
|
|
495
513
|
const cacheKey = `${role}-${preset}-${resolvedSide}-${sceneThemeId ?? 'base'}`;
|
|
@@ -566,22 +584,38 @@ export function DEFAULT_STAIR_MATERIAL(shading = 'rendered') {
|
|
|
566
584
|
export function disposeMaterial(material) {
|
|
567
585
|
material.dispose();
|
|
568
586
|
}
|
|
587
|
+
const materialCacheCleanups = new Set();
|
|
588
|
+
export function registerMaterialCacheCleanup(cleanup) {
|
|
589
|
+
materialCacheCleanups.add(cleanup);
|
|
590
|
+
return () => {
|
|
591
|
+
materialCacheCleanups.delete(cleanup);
|
|
592
|
+
};
|
|
593
|
+
}
|
|
569
594
|
export function clearMaterialCache() {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
595
|
+
const previous = [
|
|
596
|
+
...materialCache.values(),
|
|
597
|
+
...defaultMaterialCache.values(),
|
|
598
|
+
...surfaceRoleMaterialCache.values(),
|
|
599
|
+
...textureCache.values(),
|
|
600
|
+
];
|
|
573
601
|
materialCache.clear();
|
|
574
|
-
for (const material of defaultMaterialCache.values()) {
|
|
575
|
-
material.dispose();
|
|
576
|
-
}
|
|
577
602
|
defaultMaterialCache.clear();
|
|
578
|
-
for (const material of surfaceRoleMaterialCache.values()) {
|
|
579
|
-
material.dispose();
|
|
580
|
-
}
|
|
581
603
|
surfaceRoleMaterialCache.clear();
|
|
582
|
-
for (const texture of textureCache.values()) {
|
|
583
|
-
texture.dispose();
|
|
584
|
-
}
|
|
585
604
|
textureCache.clear();
|
|
586
605
|
textureLoadPromises.clear();
|
|
606
|
+
const disposals = [];
|
|
607
|
+
for (const cleanup of materialCacheCleanups) {
|
|
608
|
+
const dispose = cleanup();
|
|
609
|
+
if (dispose)
|
|
610
|
+
disposals.push(dispose);
|
|
611
|
+
}
|
|
612
|
+
// Consumers must rebuild sources and release batches before the old caches die.
|
|
613
|
+
const unsubscribe = addAfterEffect(() => {
|
|
614
|
+
unsubscribe();
|
|
615
|
+
for (const resource of previous)
|
|
616
|
+
resource.dispose();
|
|
617
|
+
for (const dispose of disposals)
|
|
618
|
+
dispose();
|
|
619
|
+
});
|
|
620
|
+
invalidate();
|
|
587
621
|
}
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MergedOutlineNode — a fork of Three.js OutlineNode that processes two object
|
|
3
|
-
* groups (primary = selected, secondary = hovered)
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* Cost comparison vs two separate OutlineNode instances:
|
|
7
|
-
* Before: depth_A + mask_A + edge_A×6 + depth_B + mask_B + edge_B×6 = 2 depth passes
|
|
8
|
-
* After: depth_AB (shared) + mask_A + edge_A×6 + mask_B + edge_B×6 = 1 depth pass
|
|
3
|
+
* groups (primary = selected, secondary = hovered), reusing scene depth when
|
|
4
|
+
* supplied and rendering masks from small private scenes. Callers without scene
|
|
5
|
+
* depth retain one shared non-selected depth pass for both groups.
|
|
9
6
|
*
|
|
10
7
|
* Additional early-outs:
|
|
11
8
|
* - Both empty → skip everything (0 passes)
|
|
12
9
|
* - Only primary → skip secondary mask/edge/blur
|
|
13
10
|
* - Only secondary → skip primary mask/edge/blur
|
|
14
11
|
*/
|
|
15
|
-
import {
|
|
12
|
+
import { Object3D } from 'three';
|
|
16
13
|
import { TempNode } from 'three/webgpu';
|
|
17
14
|
export declare class MergedOutlineNode extends TempNode {
|
|
18
15
|
static get type(): string;
|
|
@@ -26,6 +23,7 @@ export declare class MergedOutlineNode extends TempNode {
|
|
|
26
23
|
secondaryEdgeGlowNode: any;
|
|
27
24
|
downSampleRatio: number;
|
|
28
25
|
updateBeforeType: string;
|
|
26
|
+
private readonly _sceneDepthNode;
|
|
29
27
|
private readonly _depthRT;
|
|
30
28
|
private readonly _depthTexUniform;
|
|
31
29
|
private readonly _groupA;
|
|
@@ -62,6 +60,11 @@ export declare class MergedOutlineNode extends TempNode {
|
|
|
62
60
|
private readonly _compositeMatB;
|
|
63
61
|
private readonly _cacheA;
|
|
64
62
|
private readonly _cacheB;
|
|
63
|
+
private readonly _proxiesA;
|
|
64
|
+
private readonly _proxiesB;
|
|
65
|
+
private readonly _proxyMaskMaterials;
|
|
66
|
+
private readonly _maskSceneA;
|
|
67
|
+
private readonly _maskSceneB;
|
|
65
68
|
private _wroteGroupALastFrame;
|
|
66
69
|
private _wroteGroupBLastFrame;
|
|
67
70
|
private readonly _textureNodeA;
|
|
@@ -74,6 +77,8 @@ export declare class MergedOutlineNode extends TempNode {
|
|
|
74
77
|
primaryEdgeGlow?: any;
|
|
75
78
|
secondaryEdgeGlow?: any;
|
|
76
79
|
downSampleRatio?: number;
|
|
80
|
+
/** Current depth from pass(scene, camera).getTextureNode('depth'). */
|
|
81
|
+
sceneDepthNode?: any;
|
|
77
82
|
});
|
|
78
83
|
get primaryVisibleEdge(): any;
|
|
79
84
|
get primaryHiddenEdge(): any;
|
|
@@ -81,8 +86,12 @@ export declare class MergedOutlineNode extends TempNode {
|
|
|
81
86
|
get secondaryHiddenEdge(): any;
|
|
82
87
|
setSize(width: number, height: number): void;
|
|
83
88
|
updateBefore(frame: any): void;
|
|
89
|
+
private _renderMask;
|
|
90
|
+
private _syncProxies;
|
|
91
|
+
private _supportsProxies;
|
|
92
|
+
private _disposeProxyMaterial;
|
|
84
93
|
private _runEdgePipeline;
|
|
85
|
-
setup(
|
|
94
|
+
setup(builder: any): any;
|
|
86
95
|
dispose(): void;
|
|
87
96
|
private _buildCache;
|
|
88
97
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merged-outline-node.d.ts","sourceRoot":"","sources":["../../src/lib/merged-outline-node.ts"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"merged-outline-node.d.ts","sourceRoot":"","sources":["../../src/lib/merged-outline-node.ts"],"names":[],"mappings":"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"}
|