gps-plus-slam-app-framework 1.7.0 → 1.9.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/dist/{accuracy-circles-BtqOP_v1.d.ts → accuracy-circles-DkWBkF5g.d.ts} +16 -6
- package/dist/{app-selectors-ikTUQZpe.d.ts → app-selectors-BbAiCRUT.d.ts} +1 -1
- package/dist/ar/bresenham3d.d.ts +1 -1
- package/dist/ar/camera-blit-capture.d.ts +1 -1
- package/dist/ar/capability-checker.d.ts +1 -1
- package/dist/ar/capture-failure-tracker.d.ts +1 -1
- package/dist/ar/chromium-camera-access-workaround.d.ts +1 -1
- package/dist/ar/depth-grid-lookup.d.ts +1 -1
- package/dist/ar/depth-occluder.d.ts +127 -0
- package/dist/ar/depth-occluder.js +299 -0
- package/dist/ar/depth-sampler.d.ts +2 -2
- package/dist/ar/depth-sampler.js +24 -4
- package/dist/ar/depth-unprojection.d.ts +1 -1
- package/dist/ar/depth-unprojection.js +52 -21
- package/dist/ar/enable-gps-ar.d.ts +1 -1
- package/dist/ar/enable-gps-ar.js +1 -1
- package/dist/ar/frame-loop.d.ts +1 -1
- package/dist/ar/frame-loop.js +12 -2
- package/dist/ar/image-capture.d.ts +1 -1
- package/dist/ar/image-capture.js +1 -1
- package/dist/ar/image-quality.d.ts +1 -1
- package/dist/ar/image-quality.js +2 -1
- package/dist/ar/index.d.ts +32 -31
- package/dist/ar/index.js +5 -4
- package/dist/ar/occlusion-mesh-worker.d.ts +58 -0
- package/dist/ar/occlusion-mesh-worker.js +129 -0
- package/dist/ar/occupancy-grid.d.ts +2 -2
- package/dist/ar/occupancy-grid.js +287 -31
- package/dist/ar/occupancy-mesher.d.ts +2 -0
- package/dist/ar/occupancy-mesher.js +638 -0
- package/dist/ar/planar-pnp.d.ts +1 -1
- package/dist/ar/qr-debug-view.d.ts +1 -1
- package/dist/ar/qr-derived-pose.d.ts +1 -1
- package/dist/ar/qr-detection-controller.d.ts +1 -1
- package/dist/ar/qr-frontend.d.ts +1 -1
- package/dist/ar/qr-pose.d.ts +1 -1
- package/dist/ar/qr-size-depth-context.d.ts +2 -2
- package/dist/ar/qr-size-measurer.d.ts +1 -1
- package/dist/ar/replay-scene.d.ts +1 -1
- package/dist/ar/replay-scene.js +1 -1
- package/dist/ar/scene-node-names.d.ts +1 -1
- package/dist/ar/webxr-nue-basis.d.ts +1 -1
- package/dist/ar/webxr-session.d.ts +4 -4
- package/dist/ar/webxr-session.js +2 -2
- package/dist/ar/xr-camera-texture.d.ts +1 -1
- package/dist/ar/xr-error-handler.d.ts +1 -1
- package/dist/ar/xr-frame-loop.d.ts +1 -1
- package/dist/ar/xr-frame-loop.js +12 -2
- package/dist/{ar-MFpFlV7j.js → ar-BqCudtqE.js} +3 -2
- package/dist/{ar-world-group-alignment-69fgnB39.d.ts → ar-world-group-alignment-Cfg0trC3.d.ts} +1 -1
- package/dist/{capture-motion-gate-4EscNZCw.js → capture-motion-gate-_NdTSwKi.js} +17 -5
- package/dist/cell-key-DIB4rOTV.js +51 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +2 -2
- package/dist/{create-slam-app-store-n_VF63D5.d.ts → create-slam-app-store-D1QSMuKu.d.ts} +8 -9
- package/dist/{create-slam-app-store-DkCHOpvb.js → create-slam-app-store-DXiAnJwR.js} +9 -2
- package/dist/{depth-grid-lookup-DQ-IYhO3.d.ts → depth-grid-lookup-D5atpNZ3.d.ts} +1 -1
- package/dist/{depth-sampler-asc8exHt.d.ts → depth-sampler-CwObAwEA.d.ts} +33 -1
- package/dist/{depth-unprojection-DjsbJW9L.d.ts → depth-unprojection-DRdBU90S.d.ts} +1 -1
- package/dist/{enable-gps-ar-DkNhFv4Y.d.ts → enable-gps-ar-BBtRO2FJ.d.ts} +4 -4
- package/dist/{frame-conversions-DObhj8Wf.d.ts → frame-conversions-DDcNHkTb.d.ts} +1 -1
- package/dist/{fused-path-v6eOmLl3.d.ts → fused-path-C5pp0PJU.d.ts} +1 -1
- package/dist/geo/h3-proximity.d.ts +1 -1
- package/dist/geo/index.d.ts +1 -1
- package/dist/{gps-anchor-BeFO2RYa.d.ts → gps-anchor-CEjGqEVD.d.ts} +1 -1
- package/dist/{gps-ar-pose-sampler-DHMZmYAc.d.ts → gps-ar-pose-sampler-DEGNk2CI.d.ts} +1 -1
- package/dist/{gps-event-coordinator-CjWW636x.d.ts → gps-event-coordinator-BWpgBrHq.d.ts} +4 -4
- package/dist/{image-capture-CNZDrQXG.d.ts → image-capture-Bp6Pd4Md.d.ts} +3 -3
- package/dist/{image-capture-B2-b6tKK.js → image-capture-DVcuqMtX.js} +1 -1
- package/dist/{index-BODDUTvD.d.ts → index-B6iBnO_K.d.ts} +1 -1
- package/dist/index-DXPVzOpP.d.ts +2 -0
- package/dist/{index-BneSj4_5.d.ts → index-cCQWuYqy.d.ts} +3 -3
- package/dist/index.d.ts +82 -80
- package/dist/index.js +10 -8
- package/dist/{leaflet-map-overlay-CmIyiE8n.d.ts → leaflet-map-overlay-C8GS4cUy.d.ts} +64 -10
- package/dist/leaflet-map-overlay-CBWPvaX9.js +452 -0
- package/dist/lerp-utils-Qs8OhumS.d.ts +42 -0
- package/dist/map-data-1tF5gcYV.js +124 -0
- package/dist/map-data-CUnTzRIC.d.ts +78 -0
- package/dist/{map-overlay-draw-ymz1s7fG.d.ts → map-overlay-draw-6WJeq0Kg.d.ts} +1 -1
- package/dist/{null-storage-backend-B9rtyDfG.d.ts → null-storage-backend-B1-jlpin.d.ts} +2 -2
- package/dist/occlusion-mesh-kXCQ2FM1.d.ts +194 -0
- package/dist/occupancy-grid-BV7RhB7I.d.ts +194 -0
- package/dist/occupancy-mesher-C2ecWhNp.d.ts +100 -0
- package/dist/{opfs-storage-3VZh-qH6.d.ts → opfs-storage-CTkxvxN4.d.ts} +5 -0
- package/dist/{opfs-storage-backend-JJiUJo-3.d.ts → opfs-storage-backend-D6Z03fML.d.ts} +2 -2
- package/dist/{persistence-middleware-DAPTTwB2.d.ts → persistence-middleware-CG-t08X4.d.ts} +1 -1
- package/dist/{planar-pnp-my9bqULS.d.ts → planar-pnp-D7bc_rLX.d.ts} +1 -1
- package/dist/{qr-debug-view-Brl73HGO.d.ts → qr-debug-view-BJooqbiP.d.ts} +1 -1
- package/dist/{qr-derived-pose-CmxTP2m4.d.ts → qr-derived-pose-BwNWn8oV.d.ts} +2 -2
- package/dist/{qr-detected-slice-VQssZmQJ.d.ts → qr-detected-slice-TzVb8bij.d.ts} +4 -4
- package/dist/{qr-detection-controller-CDurHv8E.d.ts → qr-detection-controller-Bo4XfQTP.d.ts} +3 -3
- package/dist/{qr-frontend--fFX25mV.d.ts → qr-frontend-BPURlh3S.d.ts} +1 -1
- package/dist/{qr-pose-aggregation-B7tWJq7j.d.ts → qr-pose-aggregation-CypnmjA-.d.ts} +1 -1
- package/dist/{qr-size-depth-context-CeAG53fy.d.ts → qr-size-depth-context-apAOmbrZ.d.ts} +2 -2
- package/dist/{qr-size-measurer-DQdAsid1.d.ts → qr-size-measurer-DxiMqRUw.d.ts} +3 -3
- package/dist/{recording-options-BPCpMHLK.d.ts → recording-options-DYKWVI93.d.ts} +203 -24
- package/dist/{recording-replayer-DQKpAGyQ.d.ts → recording-replayer-BJ8Lf0QY.d.ts} +2 -2
- package/dist/{recording-slice-DaxHZvNu.d.ts → recording-slice-BW8SiLo1.d.ts} +2 -2
- package/dist/{replay-engine-CmKh_4wf.d.ts → replay-engine-DmCAc7WM.d.ts} +1 -1
- package/dist/{replay-scene-DBlDrV_x.d.ts → replay-scene-zJ8SFDjE.d.ts} +3 -3
- package/dist/sensors/absolute-orientation.d.ts +1 -1
- package/dist/sensors/absolute-orientation.js +23 -6
- package/dist/sensors/gps-error-handler.d.ts +1 -1
- package/dist/sensors/gps.d.ts +1 -1
- package/dist/sensors/index.d.ts +4 -4
- package/dist/sensors/permission-checker.d.ts +1 -1
- package/dist/state/app-selectors.d.ts +1 -1
- package/dist/state/combined-root-state.d.ts +1 -1
- package/dist/state/create-slam-app-store.d.ts +1 -1
- package/dist/state/create-slam-app-store.js +1 -1
- package/dist/state/gps-ar-pose-sampler.d.ts +3 -3
- package/dist/state/gps-event-coordinator.d.ts +1 -1
- package/dist/state/index.d.ts +19 -19
- package/dist/state/index.js +2 -2
- package/dist/state/persistence-middleware.d.ts +1 -1
- package/dist/state/qr-detected-slice.d.ts +3 -3
- package/dist/state/recording-options.d.ts +2 -2
- package/dist/state/recording-options.js +150 -19
- package/dist/state/recording-replayer.d.ts +2 -2
- package/dist/state/recording-replayer.js +1 -1
- package/dist/state/recording-slice.d.ts +1 -1
- package/dist/state/replay-engine.d.ts +1 -1
- package/dist/state/store-subscribers.d.ts +2 -2
- package/dist/state/store-subscribers.js +26 -12
- package/dist/state/subscribe-to-selector.d.ts +1 -1
- package/dist/state/tracking-quality.d.ts +1 -1
- package/dist/state/tracking-quality.js +14 -6
- package/dist/state/tracking-slice.d.ts +1 -1
- package/dist/{state-E51QT_-j.js → state-BeKvn4B-.js} +1 -1
- package/dist/storage/file-system-utils.d.ts +1 -1
- package/dist/storage/index.d.ts +8 -8
- package/dist/storage/null-storage-backend.d.ts +1 -1
- package/dist/storage/opfs-storage-backend.d.ts +1 -1
- package/dist/storage/opfs-storage.d.ts +1 -1
- package/dist/storage/opfs-storage.js +30 -1
- package/dist/storage/storage-backend.d.ts +1 -1
- package/dist/storage/zip-coverage-embed.d.ts +1 -1
- package/dist/storage/zip-export.d.ts +1 -1
- package/dist/storage/zip-reader.d.ts +2 -2
- package/dist/storage/zip-reader.js +20 -7
- package/dist/{storage-backend-BdVLD0dU.d.ts → storage-backend-sEtmM4yW.d.ts} +1 -1
- package/dist/{store-subscribers-CA6AJH_8.d.ts → store-subscribers-DJUErW-o.d.ts} +6 -3
- package/dist/{subscribe-to-selector-B6EUmQ3I.d.ts → subscribe-to-selector-dQV8SpsO.d.ts} +1 -1
- package/dist/test-utils/browser-mocks.d.ts +1 -1
- package/dist/test-utils/browser-mocks.js +2 -0
- package/dist/test-utils/zip-round-trip-helpers.d.ts +1 -1
- package/dist/{tracking-slice-BuAZxXZ5.d.ts → tracking-slice-DMkHlbny.d.ts} +1 -1
- package/dist/types/ar-types.d.ts +1 -1
- package/dist/types/geo-types.d.ts +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/utils/concurrency.d.ts +1 -1
- package/dist/utils/failure-tracker.d.ts +1 -1
- package/dist/utils/format-file-size.d.ts +1 -1
- package/dist/utils/fused-path.d.ts +1 -1
- package/dist/utils/index.d.ts +7 -7
- package/dist/utils/list-formatter.d.ts +1 -1
- package/dist/utils/logger.d.ts +1 -1
- package/dist/visualization/accuracy-circles.d.ts +1 -1
- package/dist/visualization/accuracy-circles.js +17 -8
- package/dist/visualization/alignment-lerper.d.ts +1 -1
- package/dist/visualization/ar-world-group-alignment.d.ts +1 -1
- package/dist/visualization/ar-world-group-alignment.js +1 -1
- package/dist/visualization/camera-follower.d.ts +1 -1
- package/dist/visualization/css3d-renderer-manager.d.ts +1 -1
- package/dist/visualization/frame-conversions.d.ts +1 -1
- package/dist/visualization/frustum-visibility.d.ts +1 -1
- package/dist/visualization/gps-anchor.d.ts +1 -1
- package/dist/visualization/gps-compass-cubes.d.ts +1 -1
- package/dist/visualization/gps-event-markers.d.ts +1 -1
- package/dist/visualization/gps-event-markers.js +1 -1
- package/dist/visualization/hit-test-reticle.d.ts +1 -1
- package/dist/visualization/index.d.ts +20 -19
- package/dist/visualization/index.js +4 -3
- package/dist/visualization/leaflet-map-overlay.d.ts +1 -1
- package/dist/visualization/leaflet-map-overlay.js +1 -282
- package/dist/visualization/lerp-utils.d.ts +2 -2
- package/dist/visualization/lerp-utils.js +27 -3
- package/dist/visualization/map-data.d.ts +1 -1
- package/dist/visualization/map-data.js +1 -32
- package/dist/visualization/map-overlay-draw.d.ts +1 -1
- package/dist/visualization/map-overlay-draw.js +24 -2
- package/dist/visualization/map-overlay.d.ts +1 -1
- package/dist/visualization/occluder-mesh-driver.d.ts +130 -0
- package/dist/visualization/occluder-mesh-driver.js +219 -0
- package/dist/visualization/occlusion-mesh.d.ts +2 -0
- package/dist/visualization/occlusion-mesh.js +437 -0
- package/dist/visualization/three-dispose.d.ts +1 -1
- package/dist/visualization/vis-colors.d.ts +1 -1
- package/dist/{webxr-session-DG-eNfny.js → webxr-session-BCP2XK7k.js} +88 -13
- package/dist/{webxr-session-Do5L6G3B.d.ts → webxr-session-BWCpGd-2.d.ts} +73 -10
- package/dist/{zip-reader-D9iPQwdQ.d.ts → zip-reader-BzENzMH6.d.ts} +36 -10
- package/package.json +9 -5
- package/dist/index-_Rhgoqkh.d.ts +0 -2
- package/dist/lerp-utils-BLmHhkVe.d.ts +0 -20
- package/dist/map-data-B4oEehUh.d.ts +0 -49
- package/dist/occupancy-grid-DnOc-6PU.d.ts +0 -82
- /package/dist/{absolute-orientation-CAEh840t.d.ts → absolute-orientation-BAxc15J6.d.ts} +0 -0
- /package/dist/{alignment-lerper-Bil6vbVw.d.ts → alignment-lerper-gD70k7Fq.d.ts} +0 -0
- /package/dist/{ar-types-BFX2r1wk.d.ts → ar-types-Cc5yvBwn.d.ts} +0 -0
- /package/dist/{bresenham3d-CU1Gv2W4.d.ts → bresenham3d-DGc4nIb-.d.ts} +0 -0
- /package/dist/{camera-blit-capture-NKT9H5-e.d.ts → camera-blit-capture-BimSdyih.d.ts} +0 -0
- /package/dist/{camera-follower-CqJJ7zRj.d.ts → camera-follower-DfBm2J5i.d.ts} +0 -0
- /package/dist/{capability-checker-DUQLg6gq.d.ts → capability-checker-BTTpygvZ.d.ts} +0 -0
- /package/dist/{capture-failure-tracker-gsm8q7yi.d.ts → capture-failure-tracker-_BVfhpxv.d.ts} +0 -0
- /package/dist/{capture-motion-gate-0Yl2NpQG.d.ts → capture-motion-gate-BGoAMkmf.d.ts} +0 -0
- /package/dist/{chromium-camera-access-workaround-D4K2uwwQ.d.ts → chromium-camera-access-workaround-C6yJLXz9.d.ts} +0 -0
- /package/dist/{concurrency-By0oOTZt.d.ts → concurrency-DPeGBH0X.d.ts} +0 -0
- /package/dist/{css3d-renderer-manager-B3kGNtcn.d.ts → css3d-renderer-manager-CPpVtvgs.d.ts} +0 -0
- /package/dist/{failure-tracker-BO7M7jF_.d.ts → failure-tracker-CeKf5HIc.d.ts} +0 -0
- /package/dist/{file-system-utils-DOajnMm-.d.ts → file-system-utils-DueXHxo9.d.ts} +0 -0
- /package/dist/{format-file-size-Dc98ulzB.d.ts → format-file-size-DxN-EBLc.d.ts} +0 -0
- /package/dist/{frame-loop-CpVjQ1dH.d.ts → frame-loop-7GBMBu68.d.ts} +0 -0
- /package/dist/{frustum-visibility-CeoCZchO.d.ts → frustum-visibility-CokkgS_i.d.ts} +0 -0
- /package/dist/{geo-types-3Ip1NzVR.d.ts → geo-types-DrGVu8nS.d.ts} +0 -0
- /package/dist/{gps-BBO3hKfT.d.ts → gps-CDKDQokE.d.ts} +0 -0
- /package/dist/{gps-compass-cubes-DSN87L8p.d.ts → gps-compass-cubes-1mooS3BS.d.ts} +0 -0
- /package/dist/{gps-error-handler-BbPsfw-_.d.ts → gps-error-handler-C34GQuTu.d.ts} +0 -0
- /package/dist/{gps-event-markers-Cz9RMA2k.d.ts → gps-event-markers-Di2nBzx-.d.ts} +0 -0
- /package/dist/{h3-proximity-C-j0pw1j.d.ts → h3-proximity-D0GTHQmr.d.ts} +0 -0
- /package/dist/{hit-test-reticle-DV-2TpB9.d.ts → hit-test-reticle-CaQbrhbk.d.ts} +0 -0
- /package/dist/{image-quality-smCBoFj1.d.ts → image-quality-BMx2ko9-.d.ts} +0 -0
- /package/dist/{index-BAPokxMb.d.ts → index-D74JTX4I.d.ts} +0 -0
- /package/dist/{list-formatter-KNMS0ay2.d.ts → list-formatter-DLFDnS70.d.ts} +0 -0
- /package/dist/{logger-CLnPrHiD.d.ts → logger-CqTd5Kpk.d.ts} +0 -0
- /package/dist/{map-overlay-Dh2B97MP.d.ts → map-overlay-BCQgvIgU.d.ts} +0 -0
- /package/dist/{permission-checker-CDuI8BwC.d.ts → permission-checker-B-VtjnBA.d.ts} +0 -0
- /package/dist/{qr-pose-D2rfu5DA.d.ts → qr-pose-y3vaEd6x.d.ts} +0 -0
- /package/dist/{scene-node-names-BiShOQDB.d.ts → scene-node-names-CGb-ylBd.d.ts} +0 -0
- /package/dist/{session-disposers-zv9OGXPB.js → session-disposers-BPrMplIC.js} +0 -0
- /package/dist/{three-dispose-Bt1k7WKh.d.ts → three-dispose-BMOAmPhb.d.ts} +0 -0
- /package/dist/{vis-colors-Obw2pLqT.d.ts → vis-colors-C7HI0u9_.d.ts} +0 -0
- /package/dist/{webxr-nue-basis-3nfjDJJp.d.ts → webxr-nue-basis-CaCnYxuq.d.ts} +0 -0
- /package/dist/{xr-camera-texture-Cva1q3Qj.d.ts → xr-camera-texture-q0eIDSRg.d.ts} +0 -0
- /package/dist/{xr-error-handler-CtvHpjfm.d.ts → xr-error-handler-uVGDu9IX.d.ts} +0 -0
- /package/dist/{xr-frame-loop-DIYtRcUa.d.ts → xr-frame-loop-DX3JPpAU.d.ts} +0 -0
- /package/dist/{zip-coverage-embed-DCAREVmw.d.ts → zip-coverage-embed-ncVbaZAz.d.ts} +0 -0
- /package/dist/{zip-export-ol0S_Ofd.d.ts → zip-export-CtiUnAlJ.d.ts} +0 -0
|
@@ -4,9 +4,19 @@ import L from "leaflet";
|
|
|
4
4
|
/**
|
|
5
5
|
* Style for per-event GPS accuracy circles. Radius comes from the GPS event's
|
|
6
6
|
* horizontal accuracy in meters; larger circles mean lower-quality fixes.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
*
|
|
8
|
+
* Circles are drawn **stroke-only** (no fill): Leaflet composites overlapping
|
|
9
|
+
* semi-transparent SVG fills, so N stacked filled circles reach
|
|
10
|
+
* `1 − (1 − fillOpacity)^N` opacity and paint the basemap solid on dense
|
|
11
|
+
* recordings (~90 % at ~18 overlaps with the old 0.12 fill). A fill-free
|
|
12
|
+
* outline never accumulates an opaque interior, so the basemap shows through at
|
|
13
|
+
* ANY overlap density while each accuracy radius stays readable.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* @deprecated Stroke-only since 2026-06-28 (Finding 1) — accuracy circles no
|
|
17
|
+
* longer render a fill, so this opacity is unused. Retained as an exported
|
|
18
|
+
* constant only to preserve the published API surface; do not pass it to
|
|
19
|
+
* `L.circle`. See `2026-06-28-map-rings-transparency-and-view-direction-user-feedback.md`.
|
|
10
20
|
*/
|
|
11
21
|
declare const ACCURACY_CIRCLE_FILL_OPACITY = 0.12;
|
|
12
22
|
declare const ACCURACY_CIRCLE_STROKE_OPACITY = 0.5;
|
|
@@ -23,8 +33,8 @@ interface AccuracyCircleSample {
|
|
|
23
33
|
readonly accuracy?: number;
|
|
24
34
|
}
|
|
25
35
|
/**
|
|
26
|
-
* Draw one
|
|
27
|
-
* positive number. Samples without a usable accuracy value are skipped so
|
|
36
|
+
* Draw one stroke-only (un-filled) circle per sample whose `accuracy` is a
|
|
37
|
+
* finite positive number. Samples without a usable accuracy value are skipped so
|
|
28
38
|
* pre-accuracy recordings still render their polyline.
|
|
29
39
|
*
|
|
30
40
|
* Circles are added to `map` immediately. The caller is responsible for
|
|
@@ -34,7 +44,7 @@ interface AccuracyCircleSample {
|
|
|
34
44
|
* @param map - The Leaflet map to add circles to.
|
|
35
45
|
* @param samples - GPS samples to consider; non-positive / non-finite
|
|
36
46
|
* `accuracy` values are silently skipped.
|
|
37
|
-
* @param color - CSS color string used for
|
|
47
|
+
* @param color - CSS color string used for the stroke (no fill is drawn).
|
|
38
48
|
* @returns The created `L.Circle` instances, in the order they were added.
|
|
39
49
|
* Callers that track layers for cleanup can append these to their list.
|
|
40
50
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { N as CombinedRootState, r as SlamAppRootState } from "./create-slam-app-store-
|
|
1
|
+
import { N as CombinedRootState, r as SlamAppRootState } from "./create-slam-app-store-D1QSMuKu.js";
|
|
2
2
|
import * as _$gps_plus_slam_js0 from "gps-plus-slam-js";
|
|
3
3
|
import { ArImageCapture, GpsPoint, LatLong, Matrix4, Quaternion, Vector3 } from "gps-plus-slam-js";
|
|
4
4
|
import * as _$_reduxjs_toolkit0 from "@reduxjs/toolkit";
|
package/dist/ar/bresenham3d.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as MAX_TRACE_STEPS, r as bresenham3d, t as GridCell } from "../bresenham3d-
|
|
1
|
+
import { n as MAX_TRACE_STEPS, r as bresenham3d, t as GridCell } from "../bresenham3d-DGc4nIb-.js";
|
|
2
2
|
export { GridCell, MAX_TRACE_STEPS, bresenham3d };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as computeCaptureSize, i as computeAspectFitSize, n as CameraBlitCaptureConfig, r as DEFAULT_BLIT_CONFIG, t as CameraBlitCapture } from "../camera-blit-capture-
|
|
1
|
+
import { a as computeCaptureSize, i as computeAspectFitSize, n as CameraBlitCaptureConfig, r as DEFAULT_BLIT_CONFIG, t as CameraBlitCapture } from "../camera-blit-capture-BimSdyih.js";
|
|
2
2
|
export { CameraBlitCapture, CameraBlitCaptureConfig, DEFAULT_BLIT_CONFIG, computeAspectFitSize, computeCaptureSize };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as isFullySupported, n as CapabilitySupport, r as capabilityMessage, t as CapabilityMessageOptions } from "../capability-checker-
|
|
1
|
+
import { i as isFullySupported, n as CapabilitySupport, r as capabilityMessage, t as CapabilityMessageOptions } from "../capability-checker-BTTpygvZ.js";
|
|
2
2
|
export { CapabilityMessageOptions, CapabilitySupport, capabilityMessage, isFullySupported };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as createCaptureFailureTracker, i as DEFAULT_CAPTURE_TRACKER_CONFIG, n as CaptureFailureTracker, r as CaptureFailureTrackerConfig, t as CAPTURE_FAILURE_WARNING } from "../capture-failure-tracker-
|
|
1
|
+
import { a as createCaptureFailureTracker, i as DEFAULT_CAPTURE_TRACKER_CONFIG, n as CaptureFailureTracker, r as CaptureFailureTrackerConfig, t as CAPTURE_FAILURE_WARNING } from "../capture-failure-tracker-_BVfhpxv.js";
|
|
2
2
|
export { CAPTURE_FAILURE_WARNING, CaptureFailureTracker, CaptureFailureTrackerConfig, DEFAULT_CAPTURE_TRACKER_CONFIG, createCaptureFailureTracker };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as applyChromiumProjectionLayerWorkaround, i as ChromiumProjectionLayerWorkaroundResult, n as BASELAYER_WINDOW_MIN, o as needsBaseLayerPersistence, r as ChromeVersion, s as parseChromeVersion, t as BASELAYER_WINDOW_MAX } from "../chromium-camera-access-workaround-
|
|
1
|
+
import { a as applyChromiumProjectionLayerWorkaround, i as ChromiumProjectionLayerWorkaroundResult, n as BASELAYER_WINDOW_MIN, o as needsBaseLayerPersistence, r as ChromeVersion, s as parseChromeVersion, t as BASELAYER_WINDOW_MAX } from "../chromium-camera-access-workaround-C6yJLXz9.js";
|
|
2
2
|
export { BASELAYER_WINDOW_MAX, BASELAYER_WINDOW_MIN, ChromeVersion, ChromiumProjectionLayerWorkaroundResult, applyChromiumProjectionLayerWorkaround, needsBaseLayerPersistence, parseChromeVersion };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as createDepthGridLookup, t as DepthGridLookup } from "../depth-grid-lookup-
|
|
1
|
+
import { n as createDepthGridLookup, t as DepthGridLookup } from "../depth-grid-lookup-D5atpNZ3.js";
|
|
2
2
|
export { DepthGridLookup, createDepthGridLookup };
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { t as DepthInfo } from "../depth-sampler-CwObAwEA.js";
|
|
2
|
+
import * as THREE from "three";
|
|
3
|
+
|
|
4
|
+
//#region ../src/ar/depth-occluder.d.ts
|
|
5
|
+
/** Render order of the full-screen depth writer — before virtual content
|
|
6
|
+
* (≥ 0) and at/after the persistent mesh (−2), so it composes with the mesh
|
|
7
|
+
* (nearer depth wins) and lays depth before content draws (plan §5). */
|
|
8
|
+
declare const OCCLUDER_RENDER_ORDER = -1;
|
|
9
|
+
/** The two upload formats `XRCPUDepthInformation` resolves to (plan §3a/§10). */
|
|
10
|
+
type DepthTextureFormat = 'r32f' | 'luminance-alpha';
|
|
11
|
+
/**
|
|
12
|
+
* Convert a **view-space perpendicular depth** `d` (metres in front of the camera)
|
|
13
|
+
* to a window-space depth in `[0, 1]` using the WebXR `XRView.projectionMatrix`
|
|
14
|
+
* `P` (column-major 16-tuple). This is the conversion both the per-material and
|
|
15
|
+
* the full-screen techniques need to compare the real surface against a virtual
|
|
16
|
+
* fragment's depth (plan §3b):
|
|
17
|
+
*
|
|
18
|
+
* ```
|
|
19
|
+
* z_clip = -d·P[10] + P[14]
|
|
20
|
+
* w_clip = -d·P[11] + P[15]
|
|
21
|
+
* z_ndc = z_clip / w_clip
|
|
22
|
+
* window = 0.5·z_ndc + 0.5
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* Assumes the sampled value is the perpendicular z-distance (WebXR/ARCore depth
|
|
26
|
+
* semantics). Monotonic in `d` for a standard perspective `P`, and lands in
|
|
27
|
+
* `[0, 1]` for `d ∈ [near, far]` — both pinned by the property tests.
|
|
28
|
+
*/
|
|
29
|
+
declare function metricDepthToWindowDepth(viewSpaceDepthMeters: number, projectionMatrix: ArrayLike<number>): number;
|
|
30
|
+
/**
|
|
31
|
+
* Map a normalized **screen** UV (`[0,1]²`, origin bottom-left) to the normalized
|
|
32
|
+
* **depth-buffer** UV via `XRDepthInformation.normDepthBufferFromNormView`'s
|
|
33
|
+
* `.matrix` (column-major 16-tuple). The depth texture is not 1:1 with the
|
|
34
|
+
* framebuffer (it is low-res and may be rotated), so the shader must apply this
|
|
35
|
+
* transform before sampling (plan §3c). Returns `[u, v]` after the perspective
|
|
36
|
+
* divide. The identity matrix is a fixed point (verified in tests).
|
|
37
|
+
*/
|
|
38
|
+
declare function screenUvToDepthUv(u: number, v: number, matrix: ArrayLike<number>): [number, number];
|
|
39
|
+
/**
|
|
40
|
+
* Reconstruct metres from a 16-bit depth value packed across the `luminance`
|
|
41
|
+
* (low byte) + `alpha` (high byte) channels of an `RG8` texel, then scale by
|
|
42
|
+
* `XRCPUDepthInformation.rawValueToMeters` (plan §3a/§9). `lo`/`hi` are the two
|
|
43
|
+
* `0–255` bytes; round-trips a known raw value (property-tested).
|
|
44
|
+
*/
|
|
45
|
+
declare function unpackLuminanceAlphaToMeters(lo: number, hi: number, rawValueToMeters: number): number;
|
|
46
|
+
/**
|
|
47
|
+
* Pick the `DataTexture` upload format from the resolved depth buffer's byte
|
|
48
|
+
* count (plan §3a). `float32` raw depth is 4 bytes/texel → `r32f`; the
|
|
49
|
+
* `luminance-alpha` 16-bit packing is 2 bytes/texel. We read the actual
|
|
50
|
+
* resolved layout at runtime rather than assuming the `dataFormatPreference`
|
|
51
|
+
* order, because the UA chooses (plan §3a "read it at runtime").
|
|
52
|
+
*/
|
|
53
|
+
declare function selectDepthTextureFormat(width: number, height: number, byteLength: number): DepthTextureFormat;
|
|
54
|
+
/**
|
|
55
|
+
* GLSL for the **full-screen depth-write occluder** (v1 — the "do what the
|
|
56
|
+
* persistent mesh does" path). A clip-space quad whose fragment shader samples
|
|
57
|
+
* the live depth map and writes `gl_FragDepth` from the real surface depth, so
|
|
58
|
+
* the normal depth test then hides ALL virtual content behind real surfaces —
|
|
59
|
+
* no per-material patching (2026-06-29-occlusion-debug-viz-and-live-occluder
|
|
60
|
+
* user-feedback Finding 2).
|
|
61
|
+
*
|
|
62
|
+
* The fragment math **mirrors the CI-tested pure functions**:
|
|
63
|
+
* `screenUvToDepthUv` (the `uDepthUvFromScreenUv` transform + perspective
|
|
64
|
+
* divide), the `luminance-alpha`→metres unpack, the holes policy (no/invalid
|
|
65
|
+
* depth ⇒ `discard` ⇒ never occlude, so the persistent mesh shows through), and
|
|
66
|
+
* `metricDepthToWindowDepth` (the projection-matrix metres→window-depth step).
|
|
67
|
+
*
|
|
68
|
+
* The vertex shader maps the quad's NDC position to a `[0,1]` screen UV varying,
|
|
69
|
+
* so the shader needs **no resolution uniform** (the interpolated UV *is* the
|
|
70
|
+
* normalized screen coordinate). Mono AR (one `XRView`) — plan §3c.
|
|
71
|
+
*
|
|
72
|
+
* **Device-gated tuning** (the on-device gate, not CI): the depth-UV Y
|
|
73
|
+
* orientation, the float-vs-packed default, and that `gl_FragDepth` is writable
|
|
74
|
+
* on the target (it may need an extension/`glslVersion` on some renderers).
|
|
75
|
+
*/
|
|
76
|
+
declare function buildFullscreenOcclusionShader(): {
|
|
77
|
+
vertexShader: string;
|
|
78
|
+
fragmentShader: string;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Manages the live occluder's GPU side: one small per-frame depth `DataTexture`,
|
|
82
|
+
* the shared uniform block, and the full-screen depth-write mesh. Construct once
|
|
83
|
+
* per AR session, `update(depthInfo)` each frame from the wrapped
|
|
84
|
+
* `XRCPUDepthInformation`, mount {@link getOcclusionMesh} in the AR scene, and
|
|
85
|
+
* `dispose()` on session end.
|
|
86
|
+
*
|
|
87
|
+
* The GLSL is a **device-gated first-light draft** (see the file header): its
|
|
88
|
+
* CPU-observable effects are unit-tested, but the on-device occlusion must be
|
|
89
|
+
* verified and tuned (plan §8 Iter 2–3) before `liveOcclusion` ships on.
|
|
90
|
+
*/
|
|
91
|
+
declare class DepthOccluder {
|
|
92
|
+
private readonly uniforms;
|
|
93
|
+
private fullscreenMesh;
|
|
94
|
+
private texture;
|
|
95
|
+
private textureFormat;
|
|
96
|
+
private textureWidth;
|
|
97
|
+
private textureHeight;
|
|
98
|
+
private disposed;
|
|
99
|
+
constructor();
|
|
100
|
+
/** Whether a usable depth texture has been uploaded (occlusion is live). */
|
|
101
|
+
isEnabled(): boolean;
|
|
102
|
+
/** The current upload format, or null before the first {@link update}. */
|
|
103
|
+
getTextureFormat(): DepthTextureFormat | null;
|
|
104
|
+
/**
|
|
105
|
+
* The **full-screen depth-write occluder** mesh (v1 path) — lazily created and
|
|
106
|
+
* cached. Add it to the AR scene (its vertex shader ignores transforms, so the
|
|
107
|
+
* parent node is irrelevant; the recorder adds it under `arWorldGroup`). It is
|
|
108
|
+
* `colorWrite:false` / `depthWrite:true` / `depthTest:true` at
|
|
109
|
+
* {@link OCCLUDER_RENDER_ORDER}, so it lays the real-surface depth before
|
|
110
|
+
* virtual content draws and composes with the persistent mesh (nearer wins).
|
|
111
|
+
* Shares the live uniform block, so each {@link update} reaches it.
|
|
112
|
+
*/
|
|
113
|
+
getOcclusionMesh(): THREE.Mesh;
|
|
114
|
+
/**
|
|
115
|
+
* Upload this frame's depth + metadata. No-op (and disables occlusion) when the
|
|
116
|
+
* depth info lacks the occluder fields (`data` / `rawValueToMeters` /
|
|
117
|
+
* `normDepthBufferFromNormView` / `projectionMatrix`) — e.g. a sparse-only
|
|
118
|
+
* frame — so a degraded frame can never occlude with stale or absent depth.
|
|
119
|
+
*/
|
|
120
|
+
update(depthInfo: DepthInfo): void;
|
|
121
|
+
/** (Re)create the DataTexture on a size/format change, else refresh its data. */
|
|
122
|
+
private ensureTexture;
|
|
123
|
+
/** Release the depth texture and the full-screen mesh. */
|
|
124
|
+
dispose(): void;
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
export { DepthOccluder, DepthTextureFormat, OCCLUDER_RENDER_ORDER, buildFullscreenOcclusionShader, metricDepthToWindowDepth, screenUvToDepthUv, selectDepthTextureFormat, unpackLuminanceAlphaToMeters };
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
//#region ../src/ar/depth-occluder.ts
|
|
3
|
+
/**
|
|
4
|
+
* Live CPU-depth occluder — hides virtual fragments behind the real surface the
|
|
5
|
+
* camera sees *this frame*.
|
|
6
|
+
*
|
|
7
|
+
* Companion to the **persistent** `OcclusionMesh` (`visualization/occlusion-mesh.ts`):
|
|
8
|
+
* that one meshes the accumulated occupancy grid (remembers out-of-view geometry,
|
|
9
|
+
* blocky, lagging); this one reads the per-frame `XRCPUDepthInformation` and
|
|
10
|
+
* occludes per-pixel against the surface currently in view (sharp, registration-
|
|
11
|
+
* free, no memory). They **compose** — both depth-only under `arWorldGroup`, the
|
|
12
|
+
* live occluder wins where this frame has depth, the mesh fills out-of-view / depth
|
|
13
|
+
* holes (2026-06-14-webxr-depth-occlusion-plan.md §5).
|
|
14
|
+
*
|
|
15
|
+
* **Two layers, two confidence levels:**
|
|
16
|
+
* - The **pure occlusion math** (this file's exported functions) is the CI-tested
|
|
17
|
+
* core (plan §9): the metric-depth→window-depth conversion, the screen-UV→depth-UV
|
|
18
|
+
* transform, the `luminance-alpha`→metres unpack, the depth-texture format
|
|
19
|
+
* selection, and the soft-margin / holes occlusion-strength policy. These are
|
|
20
|
+
* deterministic and property-tested.
|
|
21
|
+
* - The **{@link DepthOccluder} class** owns the per-frame `THREE.DataTexture`
|
|
22
|
+
* upload, the shared uniform block, the lifecycle (enable / dispose), and the
|
|
23
|
+
* **full-screen depth-write render path** ({@link DepthOccluder.getOcclusionMesh}):
|
|
24
|
+
* a clip-space quad that writes `gl_FragDepth` from the live depth map, so the
|
|
25
|
+
* normal depth test hides **all** virtual content behind real surfaces — the
|
|
26
|
+
* "do what the persistent mesh does" path the recorder uses (2026-06-29
|
|
27
|
+
* occlusion-debug-viz-and-live-occluder feedback Finding 2). Hard-edged.
|
|
28
|
+
* The JS-observable behaviour (texture (re)creation, uniform updates, mesh
|
|
29
|
+
* construction, disposal) is unit-tested in jsdom, but the **actual GLSL occlusion
|
|
30
|
+
* is device-gated** (plan §8 Iter 2–3): no headless GL renders it, so the shader is
|
|
31
|
+
* a first-light draft to verify/tune on-device (the `gl_FragDepth` sanity check,
|
|
32
|
+
* the depth-UV Y orientation, the float-vs-packed default). Keep
|
|
33
|
+
* `occupancy.liveOcclusion` OFF by default until that verification lands.
|
|
34
|
+
*
|
|
35
|
+
* (A second render path — a per-material soft-margin `onBeforeCompile`
|
|
36
|
+
* injection, "Phase B" — existed here as a never-wired draft until 2026-07-04
|
|
37
|
+
* and was deleted: dead code that review bots kept re-flagging. Recover it
|
|
38
|
+
* from git history if a per-material fade is ever actually built.)
|
|
39
|
+
*
|
|
40
|
+
* @see depth-occluder.ts.md for detailed documentation
|
|
41
|
+
* @see ar/depth-sampler.ts — `DepthInfo` / `wrapXRDepthInfo` (the per-frame source)
|
|
42
|
+
*/
|
|
43
|
+
/** Render order of the full-screen depth writer — before virtual content
|
|
44
|
+
* (≥ 0) and at/after the persistent mesh (−2), so it composes with the mesh
|
|
45
|
+
* (nearer depth wins) and lays depth before content draws (plan §5). */
|
|
46
|
+
const OCCLUDER_RENDER_ORDER = -1;
|
|
47
|
+
/**
|
|
48
|
+
* Convert a **view-space perpendicular depth** `d` (metres in front of the camera)
|
|
49
|
+
* to a window-space depth in `[0, 1]` using the WebXR `XRView.projectionMatrix`
|
|
50
|
+
* `P` (column-major 16-tuple). This is the conversion both the per-material and
|
|
51
|
+
* the full-screen techniques need to compare the real surface against a virtual
|
|
52
|
+
* fragment's depth (plan §3b):
|
|
53
|
+
*
|
|
54
|
+
* ```
|
|
55
|
+
* z_clip = -d·P[10] + P[14]
|
|
56
|
+
* w_clip = -d·P[11] + P[15]
|
|
57
|
+
* z_ndc = z_clip / w_clip
|
|
58
|
+
* window = 0.5·z_ndc + 0.5
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* Assumes the sampled value is the perpendicular z-distance (WebXR/ARCore depth
|
|
62
|
+
* semantics). Monotonic in `d` for a standard perspective `P`, and lands in
|
|
63
|
+
* `[0, 1]` for `d ∈ [near, far]` — both pinned by the property tests.
|
|
64
|
+
*/
|
|
65
|
+
function metricDepthToWindowDepth(viewSpaceDepthMeters, projectionMatrix) {
|
|
66
|
+
const d = viewSpaceDepthMeters;
|
|
67
|
+
const p10 = projectionMatrix[10] ?? 0;
|
|
68
|
+
const p11 = projectionMatrix[11] ?? 0;
|
|
69
|
+
const p14 = projectionMatrix[14] ?? 0;
|
|
70
|
+
const p15 = projectionMatrix[15] ?? 0;
|
|
71
|
+
return .5 * ((-d * p10 + p14) / (-d * p11 + p15)) + .5;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Map a normalized **screen** UV (`[0,1]²`, origin bottom-left) to the normalized
|
|
75
|
+
* **depth-buffer** UV via `XRDepthInformation.normDepthBufferFromNormView`'s
|
|
76
|
+
* `.matrix` (column-major 16-tuple). The depth texture is not 1:1 with the
|
|
77
|
+
* framebuffer (it is low-res and may be rotated), so the shader must apply this
|
|
78
|
+
* transform before sampling (plan §3c). Returns `[u, v]` after the perspective
|
|
79
|
+
* divide. The identity matrix is a fixed point (verified in tests).
|
|
80
|
+
*/
|
|
81
|
+
function screenUvToDepthUv(u, v, matrix) {
|
|
82
|
+
const at = (i) => matrix[i] ?? 0;
|
|
83
|
+
const x = at(0) * u + at(4) * v + at(12);
|
|
84
|
+
const y = at(1) * u + at(5) * v + at(13);
|
|
85
|
+
const w = at(3) * u + at(7) * v + at(15);
|
|
86
|
+
if (w !== 0 && Number.isFinite(w)) return [x / w, y / w];
|
|
87
|
+
return [x, y];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Reconstruct metres from a 16-bit depth value packed across the `luminance`
|
|
91
|
+
* (low byte) + `alpha` (high byte) channels of an `RG8` texel, then scale by
|
|
92
|
+
* `XRCPUDepthInformation.rawValueToMeters` (plan §3a/§9). `lo`/`hi` are the two
|
|
93
|
+
* `0–255` bytes; round-trips a known raw value (property-tested).
|
|
94
|
+
*/
|
|
95
|
+
function unpackLuminanceAlphaToMeters(lo, hi, rawValueToMeters) {
|
|
96
|
+
return ((lo & 255) + (hi & 255) * 256) * rawValueToMeters;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Pick the `DataTexture` upload format from the resolved depth buffer's byte
|
|
100
|
+
* count (plan §3a). `float32` raw depth is 4 bytes/texel → `r32f`; the
|
|
101
|
+
* `luminance-alpha` 16-bit packing is 2 bytes/texel. We read the actual
|
|
102
|
+
* resolved layout at runtime rather than assuming the `dataFormatPreference`
|
|
103
|
+
* order, because the UA chooses (plan §3a "read it at runtime").
|
|
104
|
+
*/
|
|
105
|
+
function selectDepthTextureFormat(width, height, byteLength) {
|
|
106
|
+
const texels = width * height;
|
|
107
|
+
if (texels > 0 && byteLength >= texels * 4) return "r32f";
|
|
108
|
+
return "luminance-alpha";
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* GLSL for the **full-screen depth-write occluder** (v1 — the "do what the
|
|
112
|
+
* persistent mesh does" path). A clip-space quad whose fragment shader samples
|
|
113
|
+
* the live depth map and writes `gl_FragDepth` from the real surface depth, so
|
|
114
|
+
* the normal depth test then hides ALL virtual content behind real surfaces —
|
|
115
|
+
* no per-material patching (2026-06-29-occlusion-debug-viz-and-live-occluder
|
|
116
|
+
* user-feedback Finding 2).
|
|
117
|
+
*
|
|
118
|
+
* The fragment math **mirrors the CI-tested pure functions**:
|
|
119
|
+
* `screenUvToDepthUv` (the `uDepthUvFromScreenUv` transform + perspective
|
|
120
|
+
* divide), the `luminance-alpha`→metres unpack, the holes policy (no/invalid
|
|
121
|
+
* depth ⇒ `discard` ⇒ never occlude, so the persistent mesh shows through), and
|
|
122
|
+
* `metricDepthToWindowDepth` (the projection-matrix metres→window-depth step).
|
|
123
|
+
*
|
|
124
|
+
* The vertex shader maps the quad's NDC position to a `[0,1]` screen UV varying,
|
|
125
|
+
* so the shader needs **no resolution uniform** (the interpolated UV *is* the
|
|
126
|
+
* normalized screen coordinate). Mono AR (one `XRView`) — plan §3c.
|
|
127
|
+
*
|
|
128
|
+
* **Device-gated tuning** (the on-device gate, not CI): the depth-UV Y
|
|
129
|
+
* orientation, the float-vs-packed default, and that `gl_FragDepth` is writable
|
|
130
|
+
* on the target (it may need an extension/`glslVersion` on some renderers).
|
|
131
|
+
*/
|
|
132
|
+
function buildFullscreenOcclusionShader() {
|
|
133
|
+
return {
|
|
134
|
+
vertexShader: `
|
|
135
|
+
varying vec2 vScreenUv;
|
|
136
|
+
void main() {
|
|
137
|
+
// Fullscreen clip-space quad: 'position' (PlaneGeometry(2,2)) is already in
|
|
138
|
+
// NDC [-1,1]; the interpolated [0,1] uv is the normalized screen coordinate,
|
|
139
|
+
// so no resolution uniform is needed. View/projection are intentionally
|
|
140
|
+
// ignored — this writes gl_FragDepth, not geometry depth.
|
|
141
|
+
vScreenUv = position.xy * 0.5 + 0.5;
|
|
142
|
+
gl_Position = vec4(position.xy, 0.0, 1.0);
|
|
143
|
+
}
|
|
144
|
+
`,
|
|
145
|
+
fragmentShader: `
|
|
146
|
+
precision highp float;
|
|
147
|
+
uniform sampler2D uDepthTexture;
|
|
148
|
+
uniform float uRawValueToMeters;
|
|
149
|
+
uniform mat4 uDepthUvFromScreenUv;
|
|
150
|
+
uniform mat4 uProjectionMatrix;
|
|
151
|
+
uniform float uOccluderEnabled;
|
|
152
|
+
uniform float uPackedDepth;
|
|
153
|
+
varying vec2 vScreenUv;
|
|
154
|
+
void main() {
|
|
155
|
+
// No valid depth this frame → write nothing (frame-level holes policy).
|
|
156
|
+
if (uOccluderEnabled < 0.5) { discard; }
|
|
157
|
+
// Normalized screen UV → depth-buffer UV (low-res / possibly rotated), then
|
|
158
|
+
// perspective divide — mirrors screenUvToDepthUv.
|
|
159
|
+
vec4 duv = uDepthUvFromScreenUv * vec4(vScreenUv, 0.0, 1.0);
|
|
160
|
+
vec2 depthUv = duv.xy / duv.w;
|
|
161
|
+
vec4 texel = texture2D(uDepthTexture, depthUv);
|
|
162
|
+
// Reconstruct metres: packed luminance-alpha (lo + hi*256) or float R32F.
|
|
163
|
+
float realDepthMeters = uPackedDepth > 0.5
|
|
164
|
+
? (texel.r * 255.0 + texel.g * 255.0 * 256.0) * uRawValueToMeters
|
|
165
|
+
: texel.r * uRawValueToMeters;
|
|
166
|
+
// Hole / invalid texel → never occlude (per-texel holes policy).
|
|
167
|
+
if (!(realDepthMeters > 0.0)) { discard; }
|
|
168
|
+
// metres → window depth via the WebXR projection matrix (column-major
|
|
169
|
+
// [col][row]) — mirrors metricDepthToWindowDepth.
|
|
170
|
+
float zClip = -realDepthMeters * uProjectionMatrix[2][2] + uProjectionMatrix[3][2];
|
|
171
|
+
float wClip = -realDepthMeters * uProjectionMatrix[2][3] + uProjectionMatrix[3][3];
|
|
172
|
+
gl_FragDepth = 0.5 * (zClip / wClip) + 0.5;
|
|
173
|
+
// colorWrite is off on the material; this is only here to satisfy GLSL1.
|
|
174
|
+
gl_FragColor = vec4(0.0);
|
|
175
|
+
}
|
|
176
|
+
`
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Manages the live occluder's GPU side: one small per-frame depth `DataTexture`,
|
|
181
|
+
* the shared uniform block, and the full-screen depth-write mesh. Construct once
|
|
182
|
+
* per AR session, `update(depthInfo)` each frame from the wrapped
|
|
183
|
+
* `XRCPUDepthInformation`, mount {@link getOcclusionMesh} in the AR scene, and
|
|
184
|
+
* `dispose()` on session end.
|
|
185
|
+
*
|
|
186
|
+
* The GLSL is a **device-gated first-light draft** (see the file header): its
|
|
187
|
+
* CPU-observable effects are unit-tested, but the on-device occlusion must be
|
|
188
|
+
* verified and tuned (plan §8 Iter 2–3) before `liveOcclusion` ships on.
|
|
189
|
+
*/
|
|
190
|
+
var DepthOccluder = class {
|
|
191
|
+
uniforms;
|
|
192
|
+
fullscreenMesh = null;
|
|
193
|
+
texture = null;
|
|
194
|
+
textureFormat = null;
|
|
195
|
+
textureWidth = 0;
|
|
196
|
+
textureHeight = 0;
|
|
197
|
+
disposed = false;
|
|
198
|
+
constructor() {
|
|
199
|
+
this.uniforms = {
|
|
200
|
+
uDepthTexture: { value: null },
|
|
201
|
+
uRawValueToMeters: { value: 1 },
|
|
202
|
+
uDepthUvFromScreenUv: { value: new THREE.Matrix4() },
|
|
203
|
+
uProjectionMatrix: { value: new THREE.Matrix4() },
|
|
204
|
+
uOccluderEnabled: { value: 0 },
|
|
205
|
+
uPackedDepth: { value: 0 }
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
/** Whether a usable depth texture has been uploaded (occlusion is live). */
|
|
209
|
+
isEnabled() {
|
|
210
|
+
return this.uniforms.uOccluderEnabled.value === 1;
|
|
211
|
+
}
|
|
212
|
+
/** The current upload format, or null before the first {@link update}. */
|
|
213
|
+
getTextureFormat() {
|
|
214
|
+
return this.textureFormat;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* The **full-screen depth-write occluder** mesh (v1 path) — lazily created and
|
|
218
|
+
* cached. Add it to the AR scene (its vertex shader ignores transforms, so the
|
|
219
|
+
* parent node is irrelevant; the recorder adds it under `arWorldGroup`). It is
|
|
220
|
+
* `colorWrite:false` / `depthWrite:true` / `depthTest:true` at
|
|
221
|
+
* {@link OCCLUDER_RENDER_ORDER}, so it lays the real-surface depth before
|
|
222
|
+
* virtual content draws and composes with the persistent mesh (nearer wins).
|
|
223
|
+
* Shares the live uniform block, so each {@link update} reaches it.
|
|
224
|
+
*/
|
|
225
|
+
getOcclusionMesh() {
|
|
226
|
+
if (!this.fullscreenMesh) {
|
|
227
|
+
const { vertexShader, fragmentShader } = buildFullscreenOcclusionShader();
|
|
228
|
+
const material = new THREE.ShaderMaterial({
|
|
229
|
+
uniforms: this.uniforms,
|
|
230
|
+
vertexShader,
|
|
231
|
+
fragmentShader,
|
|
232
|
+
colorWrite: false,
|
|
233
|
+
depthWrite: true,
|
|
234
|
+
depthTest: true
|
|
235
|
+
});
|
|
236
|
+
const mesh = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), material);
|
|
237
|
+
mesh.name = "live-depth-occluder";
|
|
238
|
+
mesh.frustumCulled = false;
|
|
239
|
+
mesh.renderOrder = -1;
|
|
240
|
+
this.fullscreenMesh = mesh;
|
|
241
|
+
}
|
|
242
|
+
return this.fullscreenMesh;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Upload this frame's depth + metadata. No-op (and disables occlusion) when the
|
|
246
|
+
* depth info lacks the occluder fields (`data` / `rawValueToMeters` /
|
|
247
|
+
* `normDepthBufferFromNormView` / `projectionMatrix`) — e.g. a sparse-only
|
|
248
|
+
* frame — so a degraded frame can never occlude with stale or absent depth.
|
|
249
|
+
*/
|
|
250
|
+
update(depthInfo) {
|
|
251
|
+
if (this.disposed) return;
|
|
252
|
+
const { data, rawValueToMeters, normDepthBufferFromNormView } = depthInfo;
|
|
253
|
+
if (!data || typeof rawValueToMeters !== "number" || !normDepthBufferFromNormView || !depthInfo.projectionMatrix) {
|
|
254
|
+
this.uniforms.uOccluderEnabled.value = 0;
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
const { width, height } = depthInfo;
|
|
258
|
+
const format = selectDepthTextureFormat(width, height, data.byteLength);
|
|
259
|
+
this.ensureTexture(width, height, format, data);
|
|
260
|
+
this.uniforms.uPackedDepth.value = format === "luminance-alpha" ? 1 : 0;
|
|
261
|
+
this.uniforms.uRawValueToMeters.value = rawValueToMeters;
|
|
262
|
+
this.uniforms.uDepthUvFromScreenUv.value.fromArray(normDepthBufferFromNormView);
|
|
263
|
+
this.uniforms.uProjectionMatrix.value.fromArray(depthInfo.projectionMatrix);
|
|
264
|
+
this.uniforms.uOccluderEnabled.value = 1;
|
|
265
|
+
}
|
|
266
|
+
/** (Re)create the DataTexture on a size/format change, else refresh its data. */
|
|
267
|
+
ensureTexture(width, height, format, data) {
|
|
268
|
+
if (this.texture === null || this.textureWidth !== width || this.textureHeight !== height || this.textureFormat !== format) {
|
|
269
|
+
this.texture?.dispose();
|
|
270
|
+
this.texture = format === "r32f" ? new THREE.DataTexture(new Float32Array(data), width, height, THREE.RedFormat, THREE.FloatType) : new THREE.DataTexture(new Uint8Array(data), width, height, THREE.RGFormat, THREE.UnsignedByteType);
|
|
271
|
+
this.texture.needsUpdate = true;
|
|
272
|
+
this.textureWidth = width;
|
|
273
|
+
this.textureHeight = height;
|
|
274
|
+
this.textureFormat = format;
|
|
275
|
+
this.uniforms.uDepthTexture.value = this.texture;
|
|
276
|
+
} else if (this.texture) {
|
|
277
|
+
const image = this.texture.image;
|
|
278
|
+
image.data = format === "r32f" ? new Float32Array(data) : new Uint8Array(data);
|
|
279
|
+
this.texture.needsUpdate = true;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/** Release the depth texture and the full-screen mesh. */
|
|
283
|
+
dispose() {
|
|
284
|
+
if (this.disposed) return;
|
|
285
|
+
this.disposed = true;
|
|
286
|
+
this.uniforms.uOccluderEnabled.value = 0;
|
|
287
|
+
this.uniforms.uDepthTexture.value = null;
|
|
288
|
+
this.texture?.dispose();
|
|
289
|
+
this.texture = null;
|
|
290
|
+
if (this.fullscreenMesh) {
|
|
291
|
+
this.fullscreenMesh.removeFromParent();
|
|
292
|
+
this.fullscreenMesh.geometry.dispose();
|
|
293
|
+
this.fullscreenMesh.material.dispose();
|
|
294
|
+
this.fullscreenMesh = null;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
//#endregion
|
|
299
|
+
export { DepthOccluder, OCCLUDER_RENDER_ORDER, buildFullscreenOcclusionShader, metricDepthToWindowDepth, screenUvToDepthUv, selectDepthTextureFormat, unpackLuminanceAlphaToMeters };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as DepthSample } from "../ar-types-
|
|
2
|
-
import { a as wrapXRDepthInfo, i as DepthSamplerConfig, n as DepthSampler, r as DepthSamplerCallbacks, t as DepthInfo } from "../depth-sampler-
|
|
1
|
+
import { i as DepthSample } from "../ar-types-Cc5yvBwn.js";
|
|
2
|
+
import { a as wrapXRDepthInfo, i as DepthSamplerConfig, n as DepthSampler, r as DepthSamplerCallbacks, t as DepthInfo } from "../depth-sampler-CwObAwEA.js";
|
|
3
3
|
export { DepthInfo, DepthSample, DepthSampler, DepthSamplerCallbacks, DepthSamplerConfig, wrapXRDepthInfo };
|
package/dist/ar/depth-sampler.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { extractOdomPosition } from "../state/gps-event-coordinator.js";
|
|
2
2
|
//#region ../src/ar/depth-sampler.ts
|
|
3
3
|
/**
|
|
4
|
+
* Defensively copy a 16-element column-major matrix into a plain serializable
|
|
5
|
+
* tuple. Returns undefined for missing input, the wrong length, or any
|
|
6
|
+
* non-finite entry — so an invalid (or UA-reused/garbage) source degrades to
|
|
7
|
+
* "absent" rather than poisoning downstream maths. The copy also de-aliases
|
|
8
|
+
* Float32Arrays the UA reuses across frames.
|
|
9
|
+
*/
|
|
10
|
+
function copyValidMatrix16(src) {
|
|
11
|
+
if (!src || src.length !== 16) return;
|
|
12
|
+
const copy = Array.from(src);
|
|
13
|
+
return copy.every((v) => Number.isFinite(v)) ? copy : void 0;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
4
16
|
* Wrap a raw browser XRDepthInformation object into a {@link DepthInfo}.
|
|
5
17
|
*
|
|
6
18
|
* - `getDepthInMeters` is bound to the source object (browser
|
|
@@ -9,6 +21,12 @@ import { extractOdomPosition } from "../state/gps-event-coordinator.js";
|
|
|
9
21
|
* the UA may reuse across frames) is defensively validated and copied into
|
|
10
22
|
* a plain serializable 16-tuple; invalid input (wrong length, non-finite
|
|
11
23
|
* entries) yields a DepthInfo without a matrix rather than an error.
|
|
24
|
+
* - The live-occluder metadata (`data`, `rawValueToMeters`,
|
|
25
|
+
* `normDepthBufferFromNormView`) is preserved when present and valid: `data`
|
|
26
|
+
* by live reference (no clone — see {@link DepthInfo.data}), the scale only
|
|
27
|
+
* when finite, and the UV transform's `.matrix` copied like
|
|
28
|
+
* `projectionMatrix`. The sparse grid sampler ignores all three; a source
|
|
29
|
+
* lacking them (e.g. the existing test doubles) wraps exactly as before.
|
|
12
30
|
*/
|
|
13
31
|
function wrapXRDepthInfo(raw, projectionMatrix) {
|
|
14
32
|
const wrapped = {
|
|
@@ -16,10 +34,12 @@ function wrapXRDepthInfo(raw, projectionMatrix) {
|
|
|
16
34
|
height: raw.height,
|
|
17
35
|
getDepthInMeters: raw.getDepthInMeters.bind(raw)
|
|
18
36
|
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
37
|
+
const projection = copyValidMatrix16(projectionMatrix);
|
|
38
|
+
if (projection) wrapped.projectionMatrix = projection;
|
|
39
|
+
if (raw.data instanceof ArrayBuffer) wrapped.data = raw.data;
|
|
40
|
+
if (typeof raw.rawValueToMeters === "number" && Number.isFinite(raw.rawValueToMeters)) wrapped.rawValueToMeters = raw.rawValueToMeters;
|
|
41
|
+
const uvTransform = copyValidMatrix16(raw.normDepthBufferFromNormView?.matrix);
|
|
42
|
+
if (uvTransform) wrapped.normDepthBufferFromNormView = uvTransform;
|
|
23
43
|
return wrapped;
|
|
24
44
|
}
|
|
25
45
|
const DEFAULT_CONFIG = {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as createDepthUnprojector, r as unprojectDepthPoint, t as DepthUnprojector } from "../depth-unprojection-
|
|
1
|
+
import { n as createDepthUnprojector, r as unprojectDepthPoint, t as DepthUnprojector } from "../depth-unprojection-DRdBU90S.js";
|
|
2
2
|
export { DepthUnprojector, createDepthUnprojector, unprojectDepthPoint };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mat4
|
|
1
|
+
import { mat4 } from "gl-matrix";
|
|
2
2
|
//#region ../src/ar/depth-unprojection.ts
|
|
3
3
|
/**
|
|
4
4
|
* Depth Unprojection
|
|
@@ -37,32 +37,63 @@ function createDepthUnprojector(cameraPos, cameraRot, projectionMatrix) {
|
|
|
37
37
|
if (!projectionMatrix || projectionMatrix.length !== 16) return null;
|
|
38
38
|
const invProj = mat4.invert(mat4.create(), projectionMatrix);
|
|
39
39
|
if (!invProj) return null;
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
const
|
|
40
|
+
const m0 = invProj[0];
|
|
41
|
+
const m1 = invProj[1];
|
|
42
|
+
const m2 = invProj[2];
|
|
43
|
+
const m3 = invProj[3];
|
|
44
|
+
const m4 = invProj[4];
|
|
45
|
+
const m5 = invProj[5];
|
|
46
|
+
const m6 = invProj[6];
|
|
47
|
+
const m7 = invProj[7];
|
|
48
|
+
const m8 = invProj[8];
|
|
49
|
+
const m9 = invProj[9];
|
|
50
|
+
const m10 = invProj[10];
|
|
51
|
+
const m11 = invProj[11];
|
|
52
|
+
const m12 = invProj[12];
|
|
53
|
+
const m13 = invProj[13];
|
|
54
|
+
const m14 = invProj[14];
|
|
55
|
+
const m15 = invProj[15];
|
|
56
|
+
const qx = cameraRot[0];
|
|
57
|
+
const qy = cameraRot[1];
|
|
58
|
+
const qz = cameraRot[2];
|
|
59
|
+
const qw = cameraRot[3];
|
|
60
|
+
const px = cameraPos[0];
|
|
61
|
+
const py = cameraPos[1];
|
|
62
|
+
const pz = cameraPos[2];
|
|
46
63
|
return { unproject(point) {
|
|
47
64
|
if (!isUsablePoint(point)) return null;
|
|
48
65
|
const { screenX, screenY, depthM } = point;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
const rayZ = view[2] / view[3];
|
|
66
|
+
const nx = 2 * screenX - 1;
|
|
67
|
+
const ny = 1 - 2 * screenY;
|
|
68
|
+
const viewW = m3 * nx + m7 * ny - m11 + m15;
|
|
69
|
+
if (viewW === 0) return null;
|
|
70
|
+
const rayZ = (m2 * nx + m6 * ny - m10 + m14) / viewW;
|
|
55
71
|
if (rayZ >= 0) return null;
|
|
72
|
+
const viewX = m0 * nx + m4 * ny - m8 + m12;
|
|
73
|
+
const viewY = m1 * nx + m5 * ny - m9 + m13;
|
|
56
74
|
const scale = -depthM / rayZ;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
75
|
+
const vx = viewX / viewW * scale;
|
|
76
|
+
const vy = viewY / viewW * scale;
|
|
77
|
+
const vz = -depthM;
|
|
78
|
+
let uvx = qy * vz - qz * vy;
|
|
79
|
+
let uvy = qz * vx - qx * vz;
|
|
80
|
+
let uvz = qx * vy - qy * vx;
|
|
81
|
+
const uuvx = qy * uvz - qz * uvy;
|
|
82
|
+
const uuvy = qz * uvx - qx * uvz;
|
|
83
|
+
const uuvz = qx * uvy - qy * uvx;
|
|
84
|
+
const w2 = qw * 2;
|
|
85
|
+
uvx *= w2;
|
|
86
|
+
uvy *= w2;
|
|
87
|
+
uvz *= w2;
|
|
88
|
+
const worldX = vx + uvx + uuvx * 2 + px;
|
|
89
|
+
const worldY = vy + uvy + uuvy * 2 + py;
|
|
90
|
+
const worldZ = vz + uvz + uuvz * 2 + pz;
|
|
91
|
+
if (!Number.isFinite(worldX) || !Number.isFinite(worldY) || !Number.isFinite(worldZ)) return null;
|
|
92
|
+
return [
|
|
93
|
+
worldX,
|
|
94
|
+
worldY,
|
|
95
|
+
worldZ
|
|
64
96
|
];
|
|
65
|
-
return result.every((v) => Number.isFinite(v)) ? result : null;
|
|
66
97
|
} };
|
|
67
98
|
}
|
|
68
99
|
/**
|