@relu-interactives/spatial-ecs 0.4.3 → 0.4.5
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/{chunk-6UZC6M7V.js → chunk-QIIWFP3V.js} +244 -31
- package/dist/chunk-QIIWFP3V.js.map +1 -0
- package/dist/docs/guide/mixed-reality.md +160 -3
- package/dist/docs/guide/vr-and-hand-poses.md +29 -0
- package/dist/docs/guide/world-api.md +1 -1
- package/dist/{index-n7SeH119.d.ts → index-BphKHaV-.d.ts} +65 -1
- package/dist/{index-CBdnIyI8.d.cts → index-CH7qMsQT.d.cts} +65 -1
- package/dist/index.cjs +242 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/systems/index.cjs +242 -29
- package/dist/systems/index.cjs.map +1 -1
- package/dist/systems/index.d.cts +1 -1
- package/dist/systems/index.d.ts +1 -1
- package/dist/systems/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-6UZC6M7V.js.map +0 -1
|
@@ -7464,6 +7464,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
|
|
|
7464
7464
|
const rig = world.getComponent(rigEntityId, XRRigComponent);
|
|
7465
7465
|
const rigTransform = world.getComponent(rigEntityId, TransformComponent);
|
|
7466
7466
|
if (!rig || !rigTransform) return;
|
|
7467
|
+
if (world.isXrPassthrough()) return;
|
|
7467
7468
|
const inputs = this.inputSystem.getInputs();
|
|
7468
7469
|
if (inputs.length === 0) return;
|
|
7469
7470
|
if (rig.snapTurn) {
|
|
@@ -7710,6 +7711,8 @@ var _XRSessionSystem = class _XRSessionSystem {
|
|
|
7710
7711
|
this.capabilities = NO_XR_CAPABILITIES;
|
|
7711
7712
|
/** Y compensation applied when a floor-relative space was requested but not granted. */
|
|
7712
7713
|
this.appliedOriginOffset = 0;
|
|
7714
|
+
/** The live session, so an async floor probe can tell if it has been replaced. */
|
|
7715
|
+
this.session = null;
|
|
7713
7716
|
this.inputSystem = inputSystem ?? null;
|
|
7714
7717
|
}
|
|
7715
7718
|
update(world) {
|
|
@@ -7724,10 +7727,37 @@ var _XRSessionSystem = class _XRSessionSystem {
|
|
|
7724
7727
|
}
|
|
7725
7728
|
if (presenting) {
|
|
7726
7729
|
this.dispatchInputEdges(world);
|
|
7730
|
+
this.muteDepthOcclusionColor(world);
|
|
7731
|
+
}
|
|
7732
|
+
}
|
|
7733
|
+
/**
|
|
7734
|
+
* Stop three's depth-occlusion pass from writing COLOR.
|
|
7735
|
+
*
|
|
7736
|
+
* With depth sensing granted, three draws a full-screen, head-locked mesh
|
|
7737
|
+
* every frame whose fragment shader assigns ONLY `gl_FragDepth` — that is
|
|
7738
|
+
* the whole occlusion mechanism — but its material never sets
|
|
7739
|
+
* `colorWrite: false`, so the colour output is UNDEFINED per GLSL. Desktop
|
|
7740
|
+
* drivers happen to zero it, which is why this ships unnoticed; Quest's
|
|
7741
|
+
* mobile GPU frequently leaves the last-computed temporary in the register —
|
|
7742
|
+
* the sampled DEPTH value — so the pass paints the depth camera's view over
|
|
7743
|
+
* the screen as faint head-locked contour bands. On device that reads as "a
|
|
7744
|
+
* large wireframe dome that follows my head".
|
|
7745
|
+
*
|
|
7746
|
+
* The mesh is created lazily inside three's render, so this is re-checked
|
|
7747
|
+
* every frame rather than hooked once; the write is idempotent and the
|
|
7748
|
+
* check is two property reads. Depth-only is the mesh's entire purpose —
|
|
7749
|
+
* occlusion is unaffected.
|
|
7750
|
+
*/
|
|
7751
|
+
muteDepthOcclusionColor(world) {
|
|
7752
|
+
const xr = world.getRenderer().xr;
|
|
7753
|
+
const material = xr.getDepthSensingMesh?.()?.material;
|
|
7754
|
+
if (material && material.colorWrite !== false) {
|
|
7755
|
+
material.colorWrite = false;
|
|
7727
7756
|
}
|
|
7728
7757
|
}
|
|
7729
7758
|
handleSessionStart(world) {
|
|
7730
7759
|
const session = world.getRenderer().xr.getSession();
|
|
7760
|
+
this.session = session ?? null;
|
|
7731
7761
|
const mode = session && session.environmentBlendMode !== "opaque" ? "immersive-ar" : "immersive-vr";
|
|
7732
7762
|
this.capabilities = readXrCapabilities(session ?? null, mode);
|
|
7733
7763
|
if (session && this.inputSystem) {
|
|
@@ -7766,16 +7796,16 @@ var _XRSessionSystem = class _XRSessionSystem {
|
|
|
7766
7796
|
renderer.xr.setReferenceSpaceType(wantsFloor ? "local-floor" : "local");
|
|
7767
7797
|
} catch {
|
|
7768
7798
|
}
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7799
|
+
this.appliedOriginOffset = 0;
|
|
7800
|
+
if (!wantsFloor || !session) return;
|
|
7801
|
+
const sessionAtRequest = session;
|
|
7802
|
+
session.requestReferenceSpace("local-floor").then(() => {
|
|
7803
|
+
}).catch(() => {
|
|
7804
|
+
if (this.session !== sessionAtRequest) return;
|
|
7805
|
+
if (this.appliedOriginOffset !== 0) return;
|
|
7806
|
+
this.appliedOriginOffset = rig.fallbackEyeHeight;
|
|
7777
7807
|
transform.position.y -= this.appliedOriginOffset;
|
|
7778
|
-
}
|
|
7808
|
+
});
|
|
7779
7809
|
}
|
|
7780
7810
|
handleSessionEnd(world) {
|
|
7781
7811
|
if (this.appliedOriginOffset !== 0) {
|
|
@@ -7786,6 +7816,7 @@ var _XRSessionSystem = class _XRSessionSystem {
|
|
|
7786
7816
|
}
|
|
7787
7817
|
this.appliedOriginOffset = 0;
|
|
7788
7818
|
}
|
|
7819
|
+
this.session = null;
|
|
7789
7820
|
this.capabilities = NO_XR_CAPABILITIES;
|
|
7790
7821
|
this.inputSystem?.detachSession();
|
|
7791
7822
|
this.forEachBehaviour(world, (behaviour) => {
|
|
@@ -7875,8 +7906,12 @@ function planeColliderFromPolygon(polygon) {
|
|
|
7875
7906
|
__name(planeColliderFromPolygon, "planeColliderFromPolygon");
|
|
7876
7907
|
function writeXrMeshGeometry(vertices, indices, existing) {
|
|
7877
7908
|
const geometry = existing ?? new THREE19.BufferGeometry();
|
|
7878
|
-
geometry.setAttribute(
|
|
7879
|
-
|
|
7909
|
+
geometry.setAttribute(
|
|
7910
|
+
"position",
|
|
7911
|
+
new THREE19.BufferAttribute(vertices.slice(), 3)
|
|
7912
|
+
);
|
|
7913
|
+
geometry.setIndex(new THREE19.BufferAttribute(indices.slice(), 1));
|
|
7914
|
+
geometry.deleteAttribute("normal");
|
|
7880
7915
|
geometry.computeBoundingSphere();
|
|
7881
7916
|
geometry.computeVertexNormals();
|
|
7882
7917
|
return geometry;
|
|
@@ -7902,6 +7937,42 @@ __name(decomposeXrPose, "decomposeXrPose");
|
|
|
7902
7937
|
|
|
7903
7938
|
// core/systems/XREnvironmentSystem.ts
|
|
7904
7939
|
var DEBUG_COLOR = 5088255;
|
|
7940
|
+
function debugColorFor(kind, semanticLabel) {
|
|
7941
|
+
switch (semanticLabel) {
|
|
7942
|
+
case "floor":
|
|
7943
|
+
return 5100666;
|
|
7944
|
+
// green — the surface everything should rest on
|
|
7945
|
+
case "ceiling":
|
|
7946
|
+
return 11693055;
|
|
7947
|
+
// purple
|
|
7948
|
+
case "wall":
|
|
7949
|
+
case "wall face":
|
|
7950
|
+
return DEBUG_COLOR;
|
|
7951
|
+
// blue, the family's base colour
|
|
7952
|
+
case "global mesh":
|
|
7953
|
+
return 9079442;
|
|
7954
|
+
// dim gray — raw scan, not an object
|
|
7955
|
+
default:
|
|
7956
|
+
return semanticLabel ? 16747594 : DEBUG_COLOR;
|
|
7957
|
+
}
|
|
7958
|
+
}
|
|
7959
|
+
__name(debugColorFor, "debugColorFor");
|
|
7960
|
+
var GLOBAL_MESH_DEBUG_OPACITY = 0.35;
|
|
7961
|
+
var DEBUG_RENDER_ORDER = 900;
|
|
7962
|
+
var ROOM_CAPTURE_DELAY_SECONDS = 3;
|
|
7963
|
+
var SYNTHETIC_FLOOR_EXTENT = 50;
|
|
7964
|
+
var SYNTHETIC_FLOOR_PLANE = {
|
|
7965
|
+
planeSpace: {},
|
|
7966
|
+
polygon: [
|
|
7967
|
+
{ x: -SYNTHETIC_FLOOR_EXTENT / 2, y: 0, z: -SYNTHETIC_FLOOR_EXTENT / 2 },
|
|
7968
|
+
{ x: SYNTHETIC_FLOOR_EXTENT / 2, y: 0, z: -SYNTHETIC_FLOOR_EXTENT / 2 },
|
|
7969
|
+
{ x: SYNTHETIC_FLOOR_EXTENT / 2, y: 0, z: SYNTHETIC_FLOOR_EXTENT / 2 },
|
|
7970
|
+
{ x: -SYNTHETIC_FLOOR_EXTENT / 2, y: 0, z: SYNTHETIC_FLOOR_EXTENT / 2 }
|
|
7971
|
+
],
|
|
7972
|
+
orientation: "horizontal",
|
|
7973
|
+
semanticLabel: "floor",
|
|
7974
|
+
lastChangedTime: 0
|
|
7975
|
+
};
|
|
7905
7976
|
var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
7906
7977
|
constructor() {
|
|
7907
7978
|
/** Keyed by the XRPlane/XRMesh object itself — the runtime's own identity. */
|
|
@@ -7909,17 +7980,24 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
7909
7980
|
this.meshes = /* @__PURE__ */ new Map();
|
|
7910
7981
|
this.presenting = false;
|
|
7911
7982
|
this.debugVisible = false;
|
|
7983
|
+
/** Seconds presenting, used to decide the room has genuinely nothing in it. */
|
|
7984
|
+
this.elapsed = 0;
|
|
7985
|
+
/** `initiateRoomCapture` may be called only ONCE per session. */
|
|
7986
|
+
this.roomCaptureRequested = false;
|
|
7912
7987
|
}
|
|
7913
|
-
update(world) {
|
|
7988
|
+
update(world, deltaTime = 0) {
|
|
7914
7989
|
const presenting = world.isXrPresenting();
|
|
7915
7990
|
if (!presenting) {
|
|
7916
7991
|
if (this.presenting) {
|
|
7917
7992
|
this.presenting = false;
|
|
7993
|
+
this.elapsed = 0;
|
|
7994
|
+
this.roomCaptureRequested = false;
|
|
7918
7995
|
this.clearAll(world);
|
|
7919
7996
|
}
|
|
7920
7997
|
return;
|
|
7921
7998
|
}
|
|
7922
7999
|
this.presenting = true;
|
|
8000
|
+
this.elapsed += deltaTime;
|
|
7923
8001
|
const rig = this.findRig(world);
|
|
7924
8002
|
const mode = rig?.environmentPhysics ?? "none";
|
|
7925
8003
|
if (mode === "none") {
|
|
@@ -7935,6 +8013,11 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
7935
8013
|
const frame = xr.getFrame?.();
|
|
7936
8014
|
const referenceSpace = xr.getReferenceSpace();
|
|
7937
8015
|
if (!frame || !referenceSpace) return;
|
|
8016
|
+
if (frame.detectedPlanes === void 0 && frame.detectedMeshes === void 0) {
|
|
8017
|
+
this.ensureSyntheticFloor(world);
|
|
8018
|
+
return;
|
|
8019
|
+
}
|
|
8020
|
+
this.removeSyntheticFloor(world);
|
|
7938
8021
|
const meshesAvailable = Boolean(frame.detectedMeshes);
|
|
7939
8022
|
const useMesh = (mode === "mesh" || mode === "auto") && meshesAvailable;
|
|
7940
8023
|
const usePlanes = mode === "planes" || mode === "auto" && !useMesh;
|
|
@@ -7948,11 +8031,84 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
7948
8031
|
} else if (this.meshes.size > 0) {
|
|
7949
8032
|
this.clearMap(world, this.meshes);
|
|
7950
8033
|
}
|
|
8034
|
+
this.maybeCaptureRoom(world, frame);
|
|
8035
|
+
}
|
|
8036
|
+
/**
|
|
8037
|
+
* Ask the runtime to scan the room when it turns out we have no room.
|
|
8038
|
+
*
|
|
8039
|
+
* Plane and mesh detection do NOT scan anything — they replay a scan the user
|
|
8040
|
+
* captured earlier through the system's own room setup. Most people have
|
|
8041
|
+
* never run it, and those who have may have run it in a DIFFERENT room, so a
|
|
8042
|
+
* mixed-reality experience opens against either nothing at all or someone
|
|
8043
|
+
* else's furniture, with no prompt and no error.
|
|
8044
|
+
*
|
|
8045
|
+
* `XRSession.initiateRoomCapture()` (Meta's extension) launches that setup
|
|
8046
|
+
* from inside the session, and exists precisely for this case. Contract, from
|
|
8047
|
+
* Meta's docs: callable ONCE per session, and only worth calling once we are
|
|
8048
|
+
* confident the room really is empty — the arrays populate a beat after the
|
|
8049
|
+
* session starts, so a check on frame one would fire for everyone.
|
|
8050
|
+
*/
|
|
8051
|
+
maybeCaptureRoom(world, frame) {
|
|
8052
|
+
if (this.roomCaptureRequested) return;
|
|
8053
|
+
if (this.elapsed < ROOM_CAPTURE_DELAY_SECONDS) return;
|
|
8054
|
+
if (this.planes.size > 0 || this.meshes.size > 0) return;
|
|
8055
|
+
if ((frame.detectedPlanes?.size ?? 0) > 0) return;
|
|
8056
|
+
if ((frame.detectedMeshes?.size ?? 0) > 0) return;
|
|
8057
|
+
const session = world.getRenderer().xr.getSession?.();
|
|
8058
|
+
if (typeof session?.initiateRoomCapture !== "function") return;
|
|
8059
|
+
this.roomCaptureRequested = true;
|
|
8060
|
+
session.initiateRoomCapture()?.catch(() => {
|
|
8061
|
+
});
|
|
7951
8062
|
}
|
|
7952
8063
|
/** How many pieces of real geometry are currently colliding. Script-facing. */
|
|
7953
8064
|
getDetectedCount() {
|
|
7954
8065
|
return { planes: this.planes.size, meshes: this.meshes.size };
|
|
7955
8066
|
}
|
|
8067
|
+
/**
|
|
8068
|
+
* A census of every surface currently spawned: what it is, where it sits and
|
|
8069
|
+
* roughly how big it is. Built for the template's post-session readout, so a
|
|
8070
|
+
* mystery shape on the headset can be looked up by its label instead of
|
|
8071
|
+
* guessed at — a small-radius entry at head height IS the mystery shape, and
|
|
8072
|
+
* a clean list means whatever was seen did not come from this system.
|
|
8073
|
+
*/
|
|
8074
|
+
getDebugSnapshot(world) {
|
|
8075
|
+
const snapshot = [];
|
|
8076
|
+
for (const [plane, entry] of this.planes) {
|
|
8077
|
+
const transform = world.getComponent(entry.entityId, TransformComponent);
|
|
8078
|
+
const collider = planeColliderFromPolygon(plane.polygon);
|
|
8079
|
+
snapshot.push({
|
|
8080
|
+
kind: "plane",
|
|
8081
|
+
label: plane.semanticLabel ?? null,
|
|
8082
|
+
position: transform ? { ...transform.position } : { x: 0, y: 0, z: 0 },
|
|
8083
|
+
radius: collider ? Math.hypot(collider.size.x, collider.size.z) / 2 : 0,
|
|
8084
|
+
emulated: entry.emulated
|
|
8085
|
+
});
|
|
8086
|
+
}
|
|
8087
|
+
for (const [mesh, entry] of this.meshes) {
|
|
8088
|
+
const transform = world.getComponent(entry.entityId, TransformComponent);
|
|
8089
|
+
snapshot.push({
|
|
8090
|
+
kind: "mesh",
|
|
8091
|
+
label: mesh.semanticLabel ?? null,
|
|
8092
|
+
position: transform ? { ...transform.position } : { x: 0, y: 0, z: 0 },
|
|
8093
|
+
radius: entry.geometry?.boundingSphere?.radius ?? 0,
|
|
8094
|
+
emulated: entry.emulated
|
|
8095
|
+
});
|
|
8096
|
+
}
|
|
8097
|
+
return snapshot;
|
|
8098
|
+
}
|
|
8099
|
+
/** Create the no-scan floor once; it lives in the ordinary plane map. */
|
|
8100
|
+
ensureSyntheticFloor(world) {
|
|
8101
|
+
if (this.planes.has(SYNTHETIC_FLOOR_PLANE)) return;
|
|
8102
|
+
const created = this.createPlaneEntity(world, SYNTHETIC_FLOOR_PLANE);
|
|
8103
|
+
if (created) this.planes.set(SYNTHETIC_FLOOR_PLANE, created);
|
|
8104
|
+
}
|
|
8105
|
+
/** Real scene data exists (or arrived) — the stand-in must go. */
|
|
8106
|
+
removeSyntheticFloor(world) {
|
|
8107
|
+
const entry = this.planes.get(SYNTHETIC_FLOOR_PLANE);
|
|
8108
|
+
if (!entry) return;
|
|
8109
|
+
this.destroyEntry(world, entry);
|
|
8110
|
+
this.planes.delete(SYNTHETIC_FLOOR_PLANE);
|
|
8111
|
+
}
|
|
7956
8112
|
findRig(world) {
|
|
7957
8113
|
const ids = world.query(XRRigComponent);
|
|
7958
8114
|
if (ids.length === 0) return null;
|
|
@@ -7970,9 +8126,11 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
7970
8126
|
for (const plane of detected) {
|
|
7971
8127
|
const pose = frame.getPose(plane.planeSpace, referenceSpace);
|
|
7972
8128
|
if (!pose) continue;
|
|
8129
|
+
const emulated = pose.emulatedPosition === true;
|
|
7973
8130
|
let entry = this.planes.get(plane);
|
|
7974
8131
|
const changed = plane.lastChangedTime ?? 0;
|
|
7975
8132
|
if (!entry) {
|
|
8133
|
+
if (emulated) continue;
|
|
7976
8134
|
const created = this.createPlaneEntity(world, plane);
|
|
7977
8135
|
if (!created) continue;
|
|
7978
8136
|
entry = created;
|
|
@@ -7985,11 +8143,17 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
7985
8143
|
if (collider) {
|
|
7986
8144
|
entry.geometry?.dispose();
|
|
7987
8145
|
entry.geometry = null;
|
|
7988
|
-
this.attachPlaneDebug(
|
|
8146
|
+
this.attachPlaneDebug(
|
|
8147
|
+
world,
|
|
8148
|
+
entry,
|
|
8149
|
+
collider,
|
|
8150
|
+
plane.semanticLabel ?? null
|
|
8151
|
+
);
|
|
7989
8152
|
}
|
|
7990
8153
|
}
|
|
7991
8154
|
}
|
|
7992
|
-
|
|
8155
|
+
entry.emulated = emulated;
|
|
8156
|
+
if (!emulated) this.applyPose(world, entry.entityId, pose);
|
|
7993
8157
|
}
|
|
7994
8158
|
}
|
|
7995
8159
|
syncMeshes(world, frame, referenceSpace) {
|
|
@@ -8004,9 +8168,11 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
8004
8168
|
for (const mesh of detected) {
|
|
8005
8169
|
const pose = frame.getPose(mesh.meshSpace, referenceSpace);
|
|
8006
8170
|
if (!pose) continue;
|
|
8171
|
+
const emulated = pose.emulatedPosition === true;
|
|
8007
8172
|
let entry = this.meshes.get(mesh);
|
|
8008
8173
|
const changed = mesh.lastChangedTime ?? 0;
|
|
8009
8174
|
if (!entry) {
|
|
8175
|
+
if (emulated) continue;
|
|
8010
8176
|
const created = this.createMeshEntity(world, mesh);
|
|
8011
8177
|
if (!created) continue;
|
|
8012
8178
|
entry = created;
|
|
@@ -8015,7 +8181,8 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
8015
8181
|
entry.lastChangedTime = changed;
|
|
8016
8182
|
writeXrMeshGeometry(mesh.vertices, mesh.indices, entry.geometry);
|
|
8017
8183
|
}
|
|
8018
|
-
|
|
8184
|
+
entry.emulated = emulated;
|
|
8185
|
+
if (!emulated) this.applyPose(world, entry.entityId, pose);
|
|
8019
8186
|
}
|
|
8020
8187
|
}
|
|
8021
8188
|
createPlaneEntity(world, plane) {
|
|
@@ -8035,9 +8202,12 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
8035
8202
|
entityId,
|
|
8036
8203
|
lastChangedTime: plane.lastChangedTime ?? 0,
|
|
8037
8204
|
geometry: null,
|
|
8038
|
-
material: null
|
|
8205
|
+
material: null,
|
|
8206
|
+
emulated: false
|
|
8039
8207
|
};
|
|
8040
|
-
if (this.debugVisible)
|
|
8208
|
+
if (this.debugVisible) {
|
|
8209
|
+
this.attachPlaneDebug(world, entry, collider, plane.semanticLabel ?? null);
|
|
8210
|
+
}
|
|
8041
8211
|
return entry;
|
|
8042
8212
|
}
|
|
8043
8213
|
applyPlaneCollider(world, entityId, plane) {
|
|
@@ -8062,15 +8232,36 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
8062
8232
|
createMeshEntity(world, mesh) {
|
|
8063
8233
|
if (!mesh.vertices?.length || !mesh.indices?.length) return null;
|
|
8064
8234
|
const geometry = writeXrMeshGeometry(mesh.vertices, mesh.indices);
|
|
8235
|
+
const label = mesh.semanticLabel ?? null;
|
|
8236
|
+
const isGlobalMesh = label === "global mesh";
|
|
8065
8237
|
const material = new THREE19.MeshBasicMaterial({
|
|
8066
|
-
color:
|
|
8067
|
-
wireframe: true
|
|
8238
|
+
color: debugColorFor("mesh", label),
|
|
8239
|
+
wireframe: true,
|
|
8240
|
+
// The global scan is a coarse triangle soup of the whole room; at full
|
|
8241
|
+
// strength it reads as phantom objects rather than as context.
|
|
8242
|
+
transparent: isGlobalMesh,
|
|
8243
|
+
opacity: isGlobalMesh ? GLOBAL_MESH_DEBUG_OPACITY : 1,
|
|
8244
|
+
// Depth-TESTED, deliberately. The overlay was X-ray for one release —
|
|
8245
|
+
// introduced on the theory that depth occlusion was carving it into a
|
|
8246
|
+
// head-locked dome — but that theory was falsified (the dome was the
|
|
8247
|
+
// depth mesh's unset colour output, plus emulated poses; both fixed).
|
|
8248
|
+
// X-ray had its own on-device failure: the global scan is DENSE, and a
|
|
8249
|
+
// dense wireframe at 0.35 opacity fuses into a translucent sheet — with
|
|
8250
|
+
// no depth test the walls' sheets drew through everything, stacked in
|
|
8251
|
+
// front of the user's eyes ("planes covering my face"). With the depth
|
|
8252
|
+
// buffer now holding CORRECT real-world depth, normal testing gives the
|
|
8253
|
+
// right picture: the near wall hides the far one. depthWrite stays off
|
|
8254
|
+
// so the overlay never occludes actual content.
|
|
8255
|
+
depthTest: true,
|
|
8256
|
+
depthWrite: false
|
|
8068
8257
|
});
|
|
8069
8258
|
const root = new THREE19.Group();
|
|
8070
8259
|
const child = new THREE19.Mesh(geometry, material);
|
|
8071
8260
|
child.visible = this.debugVisible;
|
|
8261
|
+
child.renderOrder = DEBUG_RENDER_ORDER;
|
|
8072
8262
|
root.add(child);
|
|
8073
8263
|
const entityId = world.createEntity();
|
|
8264
|
+
root.userData.entityId = entityId;
|
|
8074
8265
|
world.addComponents(entityId, [
|
|
8075
8266
|
new TransformComponent(),
|
|
8076
8267
|
new Object3DRef(root),
|
|
@@ -8084,29 +8275,37 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
8084
8275
|
entityId,
|
|
8085
8276
|
lastChangedTime: mesh.lastChangedTime ?? 0,
|
|
8086
8277
|
geometry,
|
|
8087
|
-
material
|
|
8278
|
+
material,
|
|
8279
|
+
emulated: false
|
|
8088
8280
|
};
|
|
8089
8281
|
}
|
|
8090
8282
|
/** A thin box so a detected plane can be SEEN, not just collided with. */
|
|
8091
|
-
attachPlaneDebug(world, entry, collider) {
|
|
8092
|
-
const
|
|
8283
|
+
attachPlaneDebug(world, entry, collider, semanticLabel) {
|
|
8284
|
+
const box = new THREE19.BoxGeometry(
|
|
8093
8285
|
collider.size.x,
|
|
8094
8286
|
collider.size.y,
|
|
8095
8287
|
collider.size.z
|
|
8096
8288
|
);
|
|
8097
|
-
const
|
|
8098
|
-
|
|
8099
|
-
|
|
8289
|
+
const geometry = new THREE19.EdgesGeometry(box);
|
|
8290
|
+
box.dispose();
|
|
8291
|
+
const material = new THREE19.LineBasicMaterial({
|
|
8292
|
+
color: debugColorFor("plane", semanticLabel),
|
|
8293
|
+
// Same depth policy as the mesh overlay — see createMeshEntity.
|
|
8294
|
+
depthTest: true,
|
|
8295
|
+
depthWrite: false
|
|
8100
8296
|
});
|
|
8101
8297
|
const root = new THREE19.Group();
|
|
8102
|
-
const child = new THREE19.
|
|
8298
|
+
const child = new THREE19.LineSegments(geometry, material);
|
|
8299
|
+
child.renderOrder = DEBUG_RENDER_ORDER;
|
|
8103
8300
|
child.position.set(collider.offset.x, collider.offset.y, collider.offset.z);
|
|
8104
8301
|
child.visible = this.debugVisible;
|
|
8105
8302
|
root.add(child);
|
|
8106
8303
|
entry.geometry = geometry;
|
|
8107
8304
|
entry.material = material;
|
|
8305
|
+
root.userData.entityId = entry.entityId;
|
|
8108
8306
|
const existing = world.getComponent(entry.entityId, Object3DRef);
|
|
8109
8307
|
if (existing) {
|
|
8308
|
+
existing.object.removeFromParent();
|
|
8110
8309
|
existing.object = root;
|
|
8111
8310
|
} else {
|
|
8112
8311
|
world.addComponent(entry.entityId, new Object3DRef(root));
|
|
@@ -8122,19 +8321,31 @@ var _XREnvironmentSystem = class _XREnvironmentSystem {
|
|
|
8122
8321
|
for (const [plane, entry] of this.planes) {
|
|
8123
8322
|
if (entry.geometry) continue;
|
|
8124
8323
|
const collider = planeColliderFromPolygon(plane.polygon);
|
|
8125
|
-
if (collider)
|
|
8324
|
+
if (collider) {
|
|
8325
|
+
this.attachPlaneDebug(
|
|
8326
|
+
world,
|
|
8327
|
+
entry,
|
|
8328
|
+
collider,
|
|
8329
|
+
plane.semanticLabel ?? null
|
|
8330
|
+
);
|
|
8331
|
+
}
|
|
8126
8332
|
}
|
|
8127
8333
|
}
|
|
8128
8334
|
for (const map of [this.planes, this.meshes]) {
|
|
8129
8335
|
for (const entry of map.values()) {
|
|
8130
8336
|
const ref = world.getComponent(entry.entityId, Object3DRef);
|
|
8131
8337
|
ref?.object.traverse((child) => {
|
|
8132
|
-
|
|
8338
|
+
const drawable = child;
|
|
8339
|
+
if (drawable.isMesh || drawable.isLine) {
|
|
8340
|
+
child.visible = this.debugVisible;
|
|
8341
|
+
}
|
|
8133
8342
|
});
|
|
8134
8343
|
}
|
|
8135
8344
|
}
|
|
8136
8345
|
}
|
|
8137
8346
|
destroyEntry(world, entry) {
|
|
8347
|
+
const ref = world.getComponent(entry.entityId, Object3DRef);
|
|
8348
|
+
ref?.object.removeFromParent();
|
|
8138
8349
|
entry.geometry?.dispose();
|
|
8139
8350
|
entry.material?.dispose();
|
|
8140
8351
|
world.destroyEntity(entry.entityId);
|
|
@@ -8311,7 +8522,9 @@ var _XRAnchorSystem = class _XRAnchorSystem {
|
|
|
8311
8522
|
continue;
|
|
8312
8523
|
}
|
|
8313
8524
|
const pose = frame.getPose(anchor.anchorSpace, referenceSpace);
|
|
8314
|
-
if (pose
|
|
8525
|
+
if (pose && pose.emulatedPosition !== true) {
|
|
8526
|
+
decomposeXrPose(pose.transform.matrix, transform);
|
|
8527
|
+
}
|
|
8315
8528
|
}
|
|
8316
8529
|
}
|
|
8317
8530
|
/** Whether this entity's pose is currently being driven by an anchor. */
|
|
@@ -9601,5 +9814,5 @@ __name(_XRHoverVisualSystem, "XRHoverVisualSystem");
|
|
|
9601
9814
|
var XRHoverVisualSystem = _XRHoverVisualSystem;
|
|
9602
9815
|
|
|
9603
9816
|
export { ADDED_NODE_MARKER_COMPONENT, ARC_GRAVITY, ARC_MAX_TIME, ARC_SPEED, ARC_STEPS, AnimationSystem, AudioSystem, Behaviour, CURLED_COS, CameraSyncSystem, DEFAULT_DIRECTION_TOLERANCE, DEFAULT_ENTER_CONFIDENCE, DEFAULT_EXIT_CONFIDENCE, DEFAULT_LOST_GRACE_SECONDS, DEFAULT_MIN_HOLD_SECONDS, EnvironmentSyncSystem, FALLBACK_HAND_SCALE, HYDRATABLE_ENTITY_KINDS, HandPoseTracker, InputSystem, InstancedMeshSystem, KeyboardKeys, LightSyncSystem, MATCH_FALLOFF, MAX_PLAUSIBLE_SPEED, MAX_SAMPLE_AGE_SECONDS, MaterialSyncSystem, MeshGeometrySystem, NODE_KEY_SEPARATOR, NO_XR_CAPABILITIES, OVERRIDE_DIFF_EXCLUDED_COMPONENTS, OVERRIDE_ROOT_EXCLUDED_COMPONENTS, ObjectVisibilitySystem, PINCH_FINGERS, PREFAB_FILE_VERSION, PREFAB_FILE_VERSION_NESTED, PhysicsSyncSystem, PostprocessingSyncSystem, RenderSystem, SCRIPT_OBJECT_ROOT_FLAG, STRAIGHT_COS, ScriptBehaviourSystem, ScriptObject, ScriptObjectSystem, TeleportAimGate, ThrowVelocityTracker, TransformSyncSystem, VELOCITY_SAMPLES, VRTeleportAreaSystem, VideoSystem, XRAnchorSystem, XRControllerVisualSystem, XREnvironmentSystem, XRHandPoseSystem, XRHitTestSystem, XRHoverVisualSystem, XRInputSystem, XRInteractionSystem, XRLocomotionSystem, XRSessionSystem, XRTeleportVisualSystem, XR_FINGERS, XR_HOVER_SHELL_FLAG, angularVelocityFrom, applyHandMaterial, arcGroundCrossing, buildComponentValueMaps, buildNodeKeyMapsFromSnapshot, buildNodeMapsFromSnapshot, canonicalizeComponentValue, clearPrefabCache, collectDiffPaths, collectEntitySubtree, collectSnapshotSubtreeIds, computeFingerCurl, computeHandShape, computeInstanceOverrides, computePalmPose, computePalmWidth, computePinch, computeSpread, createHandMaterial, decanonicalizeComponentValue, despawnPrefab, encodeOverride, estimateHandScale, findSnapshotRootEntityIds, findTopLevelNestedRegions, groupOverridePaths, hydrateWorldFromSnapshot, hydrateWorldFromSnapshotDetailed, indexSnapshotByEntity, instantiateSubtree, loadPrefab, matchHandPose, mergeComponentValue, parseOverride, parsePrefabAsset, prefabFileVersionFor, readXrCapabilities, restoreComponentState, restorePostCreateComponents, sampleTeleportArc, setPrefabAssetUrlResolver, spawnPrefab };
|
|
9604
|
-
//# sourceMappingURL=chunk-
|
|
9605
|
-
//# sourceMappingURL=chunk-
|
|
9817
|
+
//# sourceMappingURL=chunk-QIIWFP3V.js.map
|
|
9818
|
+
//# sourceMappingURL=chunk-QIIWFP3V.js.map
|