@pascal-app/viewer 1.0.0-beta.5 → 1.0.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/LICENSE +21 -0
- package/README.md +67 -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 +198 -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 +76 -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 +70 -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/capture/use-json-artifact.d.ts +2 -0
- package/dist/capture/use-json-artifact.d.ts.map +1 -0
- package/dist/capture/use-json-artifact.js +42 -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.map +1 -1
- package/dist/components/viewer/frame-limiter.js +4 -3
- package/dist/components/viewer/glb-scene.d.ts.map +1 -1
- package/dist/components/viewer/glb-scene.js +3 -1
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +70 -62
- 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 +307 -116
- 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 +130 -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 +8 -16
- 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 +16 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -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/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 +14 -30
- package/dist/lib/isolation.d.ts.map +1 -1
- package/dist/lib/isolation.js +62 -66
- 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/materials.d.ts +12 -0
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +52 -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.map +1 -1
- package/dist/lib/renderer-capability.js +4 -2
- package/dist/lib/scene-visibility.d.ts +2 -1
- package/dist/lib/scene-visibility.d.ts.map +1 -1
- package/dist/lib/scene-visibility.js +25 -2
- package/dist/lib/snapshot-pipeline.d.ts +3 -1
- package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
- package/dist/lib/snapshot-pipeline.js +32 -16
- package/dist/store/use-viewer.d.ts +5 -3
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +2 -0
- 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 +7 -3
- package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
- package/dist/systems/geometry/geometry-system.js +7 -2
- package/dist/systems/level/level-system.d.ts.map +1 -1
- package/dist/systems/level/level-system.js +1 -1
- 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.map +1 -1
- 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 +12 -1
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +24 -161
- 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 +11 -4
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +405 -153
- 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/dist/systems/zone/zone-system.d.ts.map +1 -1
- package/dist/systems/zone/zone-system.js +28 -2
- package/package.json +17 -4
- 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/index.js
CHANGED
|
@@ -17,9 +17,13 @@ export { buildGlbReferenceNodes, buildGlbReplaceNodes, } from './components/view
|
|
|
17
17
|
export { GlbScene, } from './components/viewer/glb-scene';
|
|
18
18
|
export { CROUCH_CAPSULE, CROUCH_EYE_OFFSET, CROUCH_FLOAT_HEIGHT, CROUCH_RUN_SPEED, CROUCH_WALK_SPEED, EYE_LERP_SPEED, GlbWalkthroughController, STAND_CAPSULE, STAND_CLEARANCE, STAND_FLOAT_HEIGHT, WALKTHROUGH_FOV, } from './components/viewer/glb-walkthrough-controller';
|
|
19
19
|
export { DEFAULT_HOVER_STYLES, SSGI_PARAMS, } from './components/viewer/post-processing';
|
|
20
|
+
export { SceneAtmosphere, useSceneAtmosphere, } from './components/viewer/scene-atmosphere';
|
|
20
21
|
export { SceneEnvironment } from './components/viewer/scene-environment';
|
|
22
|
+
export { SceneGroundReplacement, useSceneGroundReplacement, } from './components/viewer/scene-ground-replacement';
|
|
23
|
+
export { isViewerPresentationTextureBorrowed, markViewerPresentationTextureBorrowed, registerViewerPresentation, ViewerPresentations, viewerPresentationRegistry, } from './components/viewer/viewer-presentations';
|
|
21
24
|
export { useAssetUrl } from './hooks/use-asset-url';
|
|
22
25
|
export { useGLTFKTX2 } from './hooks/use-gltf-ktx2';
|
|
26
|
+
export { useLibraryMaterialsVersion } from './hooks/use-library-materials-version';
|
|
23
27
|
export { useNodeEvents } from './hooks/use-node-events';
|
|
24
28
|
export { ASSETS_CDN_URL, resolveAssetUrl, resolveCdnUrl } from './lib/asset-url';
|
|
25
29
|
export { backdropGradient, deepSkyColor, horizonHazeColor } from './lib/backdrop';
|
|
@@ -29,16 +33,21 @@ export { applyWorldScaleBoxUVs } from './lib/box-uv';
|
|
|
29
33
|
// because three-bvh-csg / three-mesh-bvh are viewer-only deps.
|
|
30
34
|
export { ADDITION, Brush, computeGeometryBoundsTree, csgEvaluator, csgGeometry, csgMaterials, INTERSECTION, prepareBrushForCSG, SUBTRACTION, } from './lib/csg-utils';
|
|
31
35
|
export { disposeObject3DResources } from './lib/dispose-object3d';
|
|
36
|
+
export { PERF_OVERLAY_ENABLED } from './lib/gpu-perf';
|
|
32
37
|
export { computeHeroFraming, DEFAULT_FRAMING_EXCLUDED_TYPES, heroCameraPose, temporarilyHideNodeTypes, unionRegisteredNodeBounds, } from './lib/hero-pose';
|
|
33
|
-
export { applyIsolation, clearIsolation, collectIsolationSubtree, isIsolationActive, } from './lib/isolation';
|
|
38
|
+
export { applyIsolation, clearIsolation, collectIsolationSubtree, isIsolationActive, refreshIsolation, } from './lib/isolation';
|
|
34
39
|
export { configureKtx2Support, ensureKtx2Support } from './lib/ktx2-loader';
|
|
35
|
-
export {
|
|
36
|
-
export {
|
|
40
|
+
export { LayerPassIndex } from './lib/layer-pass';
|
|
41
|
+
export { BATCHED_LAYER, GRID_LAYER, OVERLAY_LAYER, SCENE_LAYER, SHADOW_ONLY_LAYER, setSurfaceRaycastLayers, ZONE_LAYER, } from './lib/layers';
|
|
42
|
+
export { applyMaterialPresetToMaterials, BLUEPRINT_PALETTE, baseMaterial, CLAY_PALETTE, clearMaterialCache, createDefaultMaterial, createMaterial, createMaterialFromPresetRef, createSurfaceRoleMaterial, DEFAULT_CEILING_MATERIAL, DEFAULT_DOOR_MATERIAL, DEFAULT_ROOF_MATERIAL, DEFAULT_SHELF_MATERIAL, DEFAULT_SLAB_MATERIAL, DEFAULT_STAIR_MATERIAL, DEFAULT_WALL_MATERIAL, DEFAULT_WINDOW_MATERIAL, disposeMaterial, glassMaterial, MONO_PALETTE, PRESET_PALETTES, registerMaterialCacheCleanup, resolveMaterialRef, resolveSlotDefaultMaterial, resolveSurfaceColor, WHITE_PALETTE, } from './lib/materials';
|
|
37
43
|
export { mergedOutline } from './lib/merged-outline-node';
|
|
38
|
-
export
|
|
44
|
+
export * from './lib/perf-actions';
|
|
45
|
+
export { publishPerfBatchStats } from './lib/perf-panel-store';
|
|
46
|
+
export * from './lib/perf-tracks';
|
|
47
|
+
export { markPureRaycast } from './lib/pointer-events';
|
|
39
48
|
export { detectRendererCapability, initializeGpuRenderer, } from './lib/renderer-capability';
|
|
40
49
|
export { getSceneTheme, SCENE_THEME_IDS, SCENE_THEMES, } from './lib/scene-themes';
|
|
41
|
-
export { hideFromScene, showInScene } from './lib/scene-visibility';
|
|
50
|
+
export { hideFromScene, showInScene, temporarilyShowShadowOnly, } from './lib/scene-visibility';
|
|
42
51
|
export { createSnapshotPipeline, SNAPSHOT_MAX_EDGE, SNAPSHOT_MIME, SNAPSHOT_QUALITY, THUMBNAIL_HEIGHT, THUMBNAIL_WIDTH, } from './lib/snapshot-pipeline';
|
|
43
52
|
export { buildTerrainPerimeterFillGeometry, } from './lib/terrain-perimeter-fill';
|
|
44
53
|
export { getPascalTextureRef, stampPascalTextureRef, textureMapForSlot, } from './lib/texture-reference';
|
|
@@ -67,7 +76,7 @@ export { InteractiveSystem } from './systems/interactive/interactive-system';
|
|
|
67
76
|
export { ItemSystem } from './systems/item/item-system';
|
|
68
77
|
export { ItemLightSystem } from './systems/item-light/item-light-system';
|
|
69
78
|
export { LevelSystem } from './systems/level/level-system';
|
|
70
|
-
export { snapLevelsToTruePositions } from './systems/level/level-utils';
|
|
79
|
+
export { EXPLODED_GAP, getLevelPresentationY, snapLevelsToTruePositions, } from './systems/level/level-utils';
|
|
71
80
|
export { getRoofMaterialArray } from './systems/roof/roof-materials';
|
|
72
81
|
// Generic roof-segment primitives. Kinds that compose CSG against
|
|
73
82
|
// the roof shell (chimney's self-trim, dormer's virtual-segment cut)
|
|
@@ -90,7 +99,7 @@ export { getVisibleWallMaterials } from './systems/wall/wall-materials';
|
|
|
90
99
|
// definition can compose them into `def.system` without duplicating the
|
|
91
100
|
// 800+ lines of CSG / mitering logic during Phase 3. These exports are
|
|
92
101
|
// removed in Phase 6 when the legacy mount points are deleted.
|
|
93
|
-
export { drainRebuiltWalls, getPendingWallRebuildCount, WallSystem, } from './systems/wall/wall-system';
|
|
102
|
+
export { drainRebuiltWalls, getPendingWallRebuildCount, isWallInitialBuildActive, WallSystem, } from './systems/wall/wall-system';
|
|
94
103
|
export { poseWindowMovingParts, WindowAnimationSystem, } from './systems/window/window-animation-system';
|
|
95
104
|
export { buildWindowPreviewMesh, WindowSystem } from './systems/window/window-system';
|
|
96
105
|
export { ZoneSystem } from './systems/zone/zone-system';
|
package/dist/lib/csg-utils.d.ts
CHANGED
|
@@ -6,5 +6,6 @@ export declare function csgMaterials(brush: Brush): THREE.Material[];
|
|
|
6
6
|
export declare const csgEvaluator: Evaluator;
|
|
7
7
|
export declare function computeGeometryBoundsTree(geometry: THREE.BufferGeometry): void;
|
|
8
8
|
export declare function prepareBrushForCSG(brush: Brush): void;
|
|
9
|
+
export declare function subtractCsgBrush(left: Brush, right: Brush, evaluator: Evaluator): Brush;
|
|
9
10
|
export { ADDITION, Brush, INTERSECTION, SUBTRACTION } from 'three-bvh-csg';
|
|
10
11
|
//# sourceMappingURL=csg-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csg-utils.d.ts","sourceRoot":"","sources":["../../src/lib/csg-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,KAAK,KAAK,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"csg-utils.d.ts","sourceRoot":"","sources":["../../src/lib/csg-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,KAAK,KAAK,EAAE,SAAS,EAAe,MAAM,eAAe,CAAA;AA4ClE,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,KAAK,CAAC,cAAc,GAC7B,KAAK,CAAC,cAAc,CAoCtB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,cAAc,CAE9D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,CAG3D;AAED,eAAO,MAAM,YAAY,WAAkB,CAAA;AAK3C,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,KAAK,CAAC,cAAc,QAMvE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,KAAK,QAI9C;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,KAAK,CAIvF;AAID,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA"}
|
package/dist/lib/csg-utils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
-
import { Evaluator } from 'three-bvh-csg';
|
|
2
|
+
import { Evaluator, SUBTRACTION } from 'three-bvh-csg';
|
|
3
3
|
import { computeBoundsTree } from 'three-mesh-bvh';
|
|
4
4
|
/**
|
|
5
5
|
* Shared CSG primitives used by kinds whose geometry subtracts pieces
|
|
@@ -88,6 +88,11 @@ export function prepareBrushForCSG(brush) {
|
|
|
88
88
|
computeGeometryBoundsTree(brush.geometry);
|
|
89
89
|
brush.updateMatrixWorld();
|
|
90
90
|
}
|
|
91
|
+
export function subtractCsgBrush(left, right, evaluator) {
|
|
92
|
+
const result = evaluator.evaluate(left, right, SUBTRACTION);
|
|
93
|
+
prepareBrushForCSG(result);
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
91
96
|
// Re-export Brush + SUBTRACTION + ADDITION + INTERSECTION so kinds don't need a
|
|
92
97
|
// direct `three-bvh-csg` dependency.
|
|
93
98
|
export { ADDITION, Brush, INTERSECTION, SUBTRACTION } from 'three-bvh-csg';
|
package/dist/lib/gpu-perf.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gpu-perf.d.ts","sourceRoot":"","sources":["../../src/lib/gpu-perf.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,oBAAoB,SACyD,CAAA
|
|
1
|
+
{"version":3,"file":"gpu-perf.d.ts","sourceRoot":"","sources":["../../src/lib/gpu-perf.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,oBAAoB,SACyD,CAAA"}
|
package/dist/lib/gpu-perf.js
CHANGED
|
@@ -1,23 +1,9 @@
|
|
|
1
|
-
//
|
|
1
|
+
// `?perf` gate. Kept in its own module because both the overlay and
|
|
2
|
+
// `lib/perf-tracks.ts` (the instrumentation sink every system writes to) read
|
|
3
|
+
// it, and perf-tracks must not import a React component tree.
|
|
2
4
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// CPU→GPU-done delta gives a clean approximation of per-frame GPU duration
|
|
8
|
-
// regardless of which render path produced it.
|
|
5
|
+
// Timing itself lives in perf-tracks: `gpu-render` carries three's WebGPU
|
|
6
|
+
// timestamp-query total for the frame's render passes, `gpu-queue` the
|
|
7
|
+
// submit→onSubmittedWorkDone fence, `render-encode` the synchronous CPU cost of
|
|
8
|
+
// building and submitting the frame. See components/viewer/post-processing.tsx.
|
|
9
9
|
export const PERF_OVERLAY_ENABLED = typeof window !== 'undefined' && new URLSearchParams(window.location.search).has('perf');
|
|
10
|
-
const MAX_SAMPLES = 256;
|
|
11
|
-
const samples = [];
|
|
12
|
-
export function pushGpuSample(ms) {
|
|
13
|
-
samples.push(ms);
|
|
14
|
-
if (samples.length > MAX_SAMPLES)
|
|
15
|
-
samples.shift();
|
|
16
|
-
}
|
|
17
|
-
export function drainGpuSamples() {
|
|
18
|
-
if (samples.length === 0)
|
|
19
|
-
return [];
|
|
20
|
-
const out = samples.slice();
|
|
21
|
-
samples.length = 0;
|
|
22
|
-
return out;
|
|
23
|
-
}
|
package/dist/lib/isolation.d.ts
CHANGED
|
@@ -1,39 +1,23 @@
|
|
|
1
1
|
import type { AnyNodeId } from '@pascal-app/core';
|
|
2
2
|
import type { Object3D } from 'three';
|
|
3
|
-
/** True while
|
|
3
|
+
/** True while a subtree is isolated, including before its lazy meshes mount. */
|
|
4
4
|
export declare function isIsolationActive(): boolean;
|
|
5
|
-
/**
|
|
6
|
-
* Compute the union of every isolated subtree's `Object3D` descendants.
|
|
7
|
-
*
|
|
8
|
-
* Pure traversal — exported so future "focus mode" / debug tooling can
|
|
9
|
-
* reuse the same definition of "what's in the isolated set". Each root
|
|
10
|
-
* is walked via `Object3D.traverse` (the live Three.js graph, not the
|
|
11
|
-
* data-model `children` array — those can disagree when systems mount
|
|
12
|
-
* synthesized sub-meshes that the data model doesn't track).
|
|
13
|
-
*/
|
|
5
|
+
/** Include synthesized meshes below a selected native root, including hosted openings. */
|
|
14
6
|
export declare function collectIsolationSubtree(ids: ReadonlyArray<string>): Set<Object3D>;
|
|
15
7
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* isolated subtree by taking it off the scene layer.
|
|
19
|
-
*
|
|
20
|
-
* Why layers instead of `obj.visible = false`? Three.js's visibility
|
|
21
|
-
* flag *cascades* — hiding a parent hides every descendant — so we
|
|
22
|
-
* can't hide a host wall while keeping a door rendered inside it.
|
|
23
|
-
* Layer masks are per-object and don't cascade: `WebGLRenderer
|
|
24
|
-
* .projectObject` skips objects whose layer mask doesn't intersect the
|
|
25
|
-
* camera's, but always recurses into their children. So we can hide
|
|
26
|
-
* the wall and the door (hosted under it in the scene graph) still
|
|
27
|
-
* renders, with its local position relative to the wall preserved
|
|
28
|
-
* automatically by the matrix walk.
|
|
29
|
-
*
|
|
30
|
-
* The mask itself belongs to `lib/scene-visibility.ts`, which reconciles
|
|
31
|
-
* isolation with solo's shadow-caster pass, so {@link clearIsolation}
|
|
32
|
-
* gives an object back only what isolation took.
|
|
33
|
-
*
|
|
34
|
-
* Pass `null` to clear isolation (equivalent to calling
|
|
35
|
-
* {@link clearIsolation}).
|
|
8
|
+
* Select native subtrees without mutating the saved scene or cascading visibility
|
|
9
|
+
* through their hosts. The next draw also filters unregistered presentation geometry.
|
|
36
10
|
*/
|
|
37
11
|
export declare function applyIsolation(ids: ReadonlyArray<AnyNodeId> | null): void;
|
|
12
|
+
/**
|
|
13
|
+
* Reconcile immediately before viewport or snapshot rendering. Environment, sky,
|
|
14
|
+
* ground and instance batches can live outside sceneRegistry or mount asynchronously.
|
|
15
|
+
* Lights/cameras remain usable; masks do not cascade, so an isolated door can still
|
|
16
|
+
* render under its hidden wall. Collective renderers fall back to native geometry.
|
|
17
|
+
* The returned cleanup restores fog after the synchronous draw, before atmosphere
|
|
18
|
+
* owners can change it again. Do not hold this cleanup across async GPU readback.
|
|
19
|
+
*/
|
|
20
|
+
export declare function refreshIsolation(scene?: Object3D): () => void;
|
|
21
|
+
/** Restore even detached/unregistered meshes, without undoing solo or batching holds. */
|
|
38
22
|
export declare function clearIsolation(): void;
|
|
39
23
|
//# sourceMappingURL=isolation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isolation.d.ts","sourceRoot":"","sources":["../../src/lib/isolation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,OAAO,KAAK,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"isolation.d.ts","sourceRoot":"","sources":["../../src/lib/isolation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,OAAO,KAAK,EAAE,QAAQ,EAAS,MAAM,OAAO,CAAA;AAQ5C,gFAAgF;AAChF,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,0FAA0F;AAC1F,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,CASjF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,CAAC,SAAS,CAAC,GAAG,IAAI,GAAG,IAAI,CAOzE;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,IAAI,CA6B7D;AAED,yFAAyF;AACzF,wBAAgB,cAAc,IAAI,IAAI,CAKrC"}
|
package/dist/lib/isolation.js
CHANGED
|
@@ -1,91 +1,87 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { sceneRegistry } from '@pascal-app/core';
|
|
3
3
|
import { hideFromScene, showInScene } from './scene-visibility';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
/** True while an isolation filter is applied (see {@link applyIsolation}). */
|
|
4
|
+
let isolatedIds = null;
|
|
5
|
+
let heldObjects = new Set();
|
|
6
|
+
let liveScene;
|
|
7
|
+
const noop = () => { };
|
|
8
|
+
/** True while a subtree is isolated, including before its lazy meshes mount. */
|
|
10
9
|
export function isIsolationActive() {
|
|
11
|
-
return
|
|
10
|
+
return isolatedIds !== null;
|
|
12
11
|
}
|
|
13
|
-
/**
|
|
14
|
-
* Compute the union of every isolated subtree's `Object3D` descendants.
|
|
15
|
-
*
|
|
16
|
-
* Pure traversal — exported so future "focus mode" / debug tooling can
|
|
17
|
-
* reuse the same definition of "what's in the isolated set". Each root
|
|
18
|
-
* is walked via `Object3D.traverse` (the live Three.js graph, not the
|
|
19
|
-
* data-model `children` array — those can disagree when systems mount
|
|
20
|
-
* synthesized sub-meshes that the data model doesn't track).
|
|
21
|
-
*/
|
|
12
|
+
/** Include synthesized meshes below a selected native root, including hosted openings. */
|
|
22
13
|
export function collectIsolationSubtree(ids) {
|
|
23
14
|
const keep = new Set();
|
|
24
15
|
for (const id of ids) {
|
|
25
16
|
const root = sceneRegistry.nodes.get(id);
|
|
26
|
-
|
|
27
|
-
continue;
|
|
28
|
-
root.traverse((child) => {
|
|
17
|
+
root?.traverse((child) => {
|
|
29
18
|
keep.add(child);
|
|
30
19
|
});
|
|
31
20
|
}
|
|
32
21
|
return keep;
|
|
33
22
|
}
|
|
34
23
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* isolated subtree by taking it off the scene layer.
|
|
38
|
-
*
|
|
39
|
-
* Why layers instead of `obj.visible = false`? Three.js's visibility
|
|
40
|
-
* flag *cascades* — hiding a parent hides every descendant — so we
|
|
41
|
-
* can't hide a host wall while keeping a door rendered inside it.
|
|
42
|
-
* Layer masks are per-object and don't cascade: `WebGLRenderer
|
|
43
|
-
* .projectObject` skips objects whose layer mask doesn't intersect the
|
|
44
|
-
* camera's, but always recurses into their children. So we can hide
|
|
45
|
-
* the wall and the door (hosted under it in the scene graph) still
|
|
46
|
-
* renders, with its local position relative to the wall preserved
|
|
47
|
-
* automatically by the matrix walk.
|
|
48
|
-
*
|
|
49
|
-
* The mask itself belongs to `lib/scene-visibility.ts`, which reconciles
|
|
50
|
-
* isolation with solo's shadow-caster pass, so {@link clearIsolation}
|
|
51
|
-
* gives an object back only what isolation took.
|
|
52
|
-
*
|
|
53
|
-
* Pass `null` to clear isolation (equivalent to calling
|
|
54
|
-
* {@link clearIsolation}).
|
|
24
|
+
* Select native subtrees without mutating the saved scene or cascading visibility
|
|
25
|
+
* through their hosts. The next draw also filters unregistered presentation geometry.
|
|
55
26
|
*/
|
|
56
27
|
export function applyIsolation(ids) {
|
|
57
28
|
if (ids == null || ids.length === 0) {
|
|
58
29
|
clearIsolation();
|
|
59
30
|
return;
|
|
60
31
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// hide it and every descendant — *except* descendants that are
|
|
64
|
-
// themselves in `keep` (a kept node nested under a non-kept host:
|
|
65
|
-
// the isolated door under the hidden wall).
|
|
66
|
-
for (const [, obj] of sceneRegistry.nodes) {
|
|
67
|
-
if (keep.has(obj))
|
|
68
|
-
continue;
|
|
69
|
-
hideRecursive(obj, keep);
|
|
70
|
-
}
|
|
71
|
-
isolationActive = true;
|
|
32
|
+
isolatedIds = [...ids];
|
|
33
|
+
refreshIsolation();
|
|
72
34
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Reconcile immediately before viewport or snapshot rendering. Environment, sky,
|
|
37
|
+
* ground and instance batches can live outside sceneRegistry or mount asynchronously.
|
|
38
|
+
* Lights/cameras remain usable; masks do not cascade, so an isolated door can still
|
|
39
|
+
* render under its hidden wall. Collective renderers fall back to native geometry.
|
|
40
|
+
* The returned cleanup restores fog after the synchronous draw, before atmosphere
|
|
41
|
+
* owners can change it again. Do not hold this cleanup across async GPU readback.
|
|
42
|
+
*/
|
|
43
|
+
export function refreshIsolation(scene) {
|
|
44
|
+
if (!isolatedIds)
|
|
45
|
+
return noop;
|
|
46
|
+
if (scene)
|
|
47
|
+
liveScene = scene;
|
|
48
|
+
const keep = collectIsolationSubtree(isolatedIds);
|
|
49
|
+
const visited = new Set();
|
|
50
|
+
const hidden = new Set();
|
|
51
|
+
const visit = (object) => {
|
|
52
|
+
if (visited.has(object))
|
|
53
|
+
return;
|
|
54
|
+
visited.add(object);
|
|
55
|
+
const flags = object;
|
|
56
|
+
if (keep.has(object) || flags.isLight || flags.isCamera)
|
|
57
|
+
return;
|
|
58
|
+
hideFromScene(object, 'isolated');
|
|
59
|
+
hidden.add(object);
|
|
60
|
+
};
|
|
61
|
+
liveScene?.traverse(visit);
|
|
62
|
+
// Also covers not-yet-attached registered roots and imperative callers without a scene.
|
|
63
|
+
for (const object of sceneRegistry.nodes.values())
|
|
64
|
+
object.traverse(visit);
|
|
65
|
+
for (const object of heldObjects)
|
|
66
|
+
if (!hidden.has(object))
|
|
67
|
+
showInScene(object, 'isolated');
|
|
68
|
+
heldObjects = hidden;
|
|
69
|
+
const atmosphere = scene;
|
|
70
|
+
if (!atmosphere?.isScene)
|
|
71
|
+
return noop;
|
|
72
|
+
const { fog, fogNode } = atmosphere;
|
|
73
|
+
atmosphere.fog = null;
|
|
74
|
+
atmosphere.fogNode = null;
|
|
75
|
+
return () => {
|
|
76
|
+
atmosphere.fog = fog;
|
|
77
|
+
atmosphere.fogNode = fogNode;
|
|
78
|
+
};
|
|
80
79
|
}
|
|
80
|
+
/** Restore even detached/unregistered meshes, without undoing solo or batching holds. */
|
|
81
81
|
export function clearIsolation() {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
showInScene(child, 'isolated');
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
isolationActive = false;
|
|
82
|
+
for (const object of heldObjects)
|
|
83
|
+
showInScene(object, 'isolated');
|
|
84
|
+
heldObjects.clear();
|
|
85
|
+
isolatedIds = null;
|
|
86
|
+
liveScene = undefined;
|
|
91
87
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Camera, Object3D, type Scene } from 'three';
|
|
2
|
+
import { type NodeFrame, PassNode } from 'three/webgpu';
|
|
3
|
+
export declare class LayerPassIndex {
|
|
4
|
+
readonly source: Scene;
|
|
5
|
+
private readonly members;
|
|
6
|
+
private readonly cleanups;
|
|
7
|
+
constructor(source: Scene, layers: number[]);
|
|
8
|
+
register(subtree: Object3D): void;
|
|
9
|
+
private attach;
|
|
10
|
+
private detach;
|
|
11
|
+
prepare(layer: number, roots: Object3D[]): {
|
|
12
|
+
drawable: boolean;
|
|
13
|
+
shadowLight: boolean;
|
|
14
|
+
};
|
|
15
|
+
dispose(): void;
|
|
16
|
+
}
|
|
17
|
+
export declare class LayerPassNode extends PassNode {
|
|
18
|
+
private readonly index;
|
|
19
|
+
private readonly layer;
|
|
20
|
+
private readonly mainPass;
|
|
21
|
+
private readonly roots;
|
|
22
|
+
private readonly size;
|
|
23
|
+
private needsClear;
|
|
24
|
+
constructor(index: LayerPassIndex, camera: Camera, layer: number, mainPass: PassNode);
|
|
25
|
+
dispose(): void;
|
|
26
|
+
updateBefore(frame: NodeFrame): undefined;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=layer-pass.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layer-pass.d.ts","sourceRoot":"","sources":["../../src/lib/layer-pass.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,MAAM,EAAiB,QAAQ,EAAE,KAAK,KAAK,EAAW,MAAM,OAAO,CAAA;AACjF,OAAO,EAAE,KAAK,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAoBvD,qBAAa,cAAc;IAKvB,QAAQ,CAAC,MAAM,EAAE,KAAK;IAJxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;gBAGhD,MAAM,EAAE,KAAK,EACtB,MAAM,EAAE,MAAM,EAAE;IAWlB,QAAQ,CAAC,OAAO,EAAE,QAAQ;IAU1B,OAAO,CAAC,MAAM,CA2Cb;IAED,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE;;;;IAoCxC,OAAO;CAIR;AAiBD,qBAAa,aAAc,SAAQ,QAAQ;IAMvC,OAAO,CAAC,QAAQ,CAAC,KAAK;IAEtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAR3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,UAAU,CAAO;gBAGN,KAAK,EAAE,cAAc,EACtC,MAAM,EAAE,MAAM,EACG,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ;IAc5B,OAAO;IAKP,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS;CAgEnD"}
|
|
@@ -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
|
+
}
|