@relu-interactives/spatial-ecs 0.3.5 → 0.3.7
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/{System-vrU46Vuw.d.cts → System-TmC2EijF.d.cts} +2 -2
- package/dist/{System-vrU46Vuw.d.ts → System-TmC2EijF.d.ts} +2 -2
- package/dist/{XRRig-2686IqLQ.d.cts → XRInteractor-CCUzSqg9.d.ts} +96 -2
- package/dist/{XRRig-D2QURXl1.d.ts → XRInteractor-I2q6TKtF.d.cts} +96 -2
- package/dist/{chunk-4BZYK3JP.js → chunk-FQTOC7HK.js} +135 -88
- package/dist/chunk-FQTOC7HK.js.map +1 -0
- package/dist/{chunk-2LVFGVWI.js → chunk-JRJ3CL5H.js} +3 -3
- package/dist/{chunk-2LVFGVWI.js.map → chunk-JRJ3CL5H.js.map} +1 -1
- package/dist/{chunk-6QC2PJLD.js → chunk-N4GKZ7IV.js} +29 -3
- package/dist/chunk-N4GKZ7IV.js.map +1 -0
- package/dist/{chunk-G53MZVKQ.js → chunk-O6FJA4XW.js} +367 -53
- package/dist/chunk-O6FJA4XW.js.map +1 -0
- package/dist/components/index.cjs +26 -0
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +3 -3
- package/dist/components/index.d.ts +3 -3
- package/dist/components/index.js +1 -1
- package/dist/factories/index.cjs +185 -112
- package/dist/factories/index.cjs.map +1 -1
- package/dist/factories/index.d.cts +7 -3
- package/dist/factories/index.d.ts +7 -3
- package/dist/factories/index.js +3 -3
- package/dist/{index-BvCmmuJ0.d.cts → index-B9nwRDf9.d.cts} +65 -14
- package/dist/{index-BtKOaHfY.d.ts → index-BltjPEhg.d.cts} +10 -3
- package/dist/{index-Xu238jLn.d.cts → index-W8pUajCW.d.ts} +10 -3
- package/dist/{index-B-CViRMx.d.ts → index-_q9TVDI5.d.ts} +65 -14
- package/dist/index.cjs +684 -293
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -9
- package/dist/index.d.ts +35 -9
- package/dist/index.js +8 -8
- package/dist/systems/index.cjs +386 -48
- package/dist/systems/index.cjs.map +1 -1
- package/dist/systems/index.d.cts +2 -2
- package/dist/systems/index.d.ts +2 -2
- package/dist/systems/index.js +3 -3
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/worldSnapshotUtils.d.cts +1 -1
- package/dist/worldSnapshotUtils.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-4BZYK3JP.js.map +0 -1
- package/dist/chunk-6QC2PJLD.js.map +0 -1
- package/dist/chunk-G53MZVKQ.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resolveDracoDecoderPath, applyTransform, SHARED_MODEL_RESOURCE_FLAG } from './chunk-
|
|
2
|
-
import { AnimationComponent, ModelComponent, CameraComponent, Object3DRef, Environment, Postprocessing, TransformComponent, PhysicsComponent, setPhysicsLiveRef, LightComponent, MaterialComponent, DEFAULT_MESH_GEOMETRY_PARAMETERS, MeshGeometryComponent, InstancedMeshComponent, ParentId, ScriptComponent, ScriptObjectComponent, XRRigComponent, VRTeleportAreaComponent, XRInteractableComponent, InstanceSlotComponent, Name, ImageComponent, SpriteComponent, VideoComponent, AudioComponent, ImageTarget, Selectable, PrefabNode, PrefabInstance } from './chunk-
|
|
1
|
+
import { resolveDracoDecoderPath, applyTransform, SHARED_MODEL_RESOURCE_FLAG } from './chunk-JRJ3CL5H.js';
|
|
2
|
+
import { AnimationComponent, ModelComponent, CameraComponent, Object3DRef, Environment, Postprocessing, TransformComponent, PhysicsComponent, setPhysicsLiveRef, LightComponent, MaterialComponent, DEFAULT_MESH_GEOMETRY_PARAMETERS, MeshGeometryComponent, InstancedMeshComponent, ParentId, ScriptComponent, ScriptObjectComponent, XRRigComponent, VRTeleportAreaComponent, XRInteractableComponent, XRInteractorComponent, XRInteractorSideComponent, InstanceSlotComponent, Name, ImageComponent, SpriteComponent, VideoComponent, AudioComponent, ImageTarget, Selectable, PrefabNode, PrefabInstance } from './chunk-N4GKZ7IV.js';
|
|
3
3
|
import { __name } from './chunk-OY7ZODZP.js';
|
|
4
4
|
import * as THREE7 from 'three';
|
|
5
5
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
@@ -2791,6 +2791,14 @@ function buildComponentValueMaps(snapshot) {
|
|
|
2791
2791
|
snapshot.components,
|
|
2792
2792
|
"XRInteractableComponent"
|
|
2793
2793
|
),
|
|
2794
|
+
xrInteractorValues: readByComponent(
|
|
2795
|
+
snapshot.components,
|
|
2796
|
+
"XRInteractorComponent"
|
|
2797
|
+
),
|
|
2798
|
+
xrInteractorSideValues: readByComponent(
|
|
2799
|
+
snapshot.components,
|
|
2800
|
+
"XRInteractorSideComponent"
|
|
2801
|
+
),
|
|
2794
2802
|
instancedMeshValues: readByComponent(snapshot.components, "InstancedMeshComponent"),
|
|
2795
2803
|
instanceSlotValues: readByComponent(snapshot.components, "InstanceSlotComponent"),
|
|
2796
2804
|
prefabNodeValues: readByComponent(snapshot.components, "PrefabNode"),
|
|
@@ -2977,6 +2985,60 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
|
|
|
2977
2985
|
}
|
|
2978
2986
|
}
|
|
2979
2987
|
}
|
|
2988
|
+
{
|
|
2989
|
+
const sourceInteractor = asRecord(
|
|
2990
|
+
values.xrInteractorValues.get(sourceEntityId)
|
|
2991
|
+
);
|
|
2992
|
+
const interactor = world.getComponent(targetEntityId, XRInteractorComponent);
|
|
2993
|
+
if (sourceInteractor && interactor) {
|
|
2994
|
+
if (typeof sourceInteractor.interactorType === "string") {
|
|
2995
|
+
interactor.interactorType = sourceInteractor.interactorType;
|
|
2996
|
+
}
|
|
2997
|
+
if (typeof sourceInteractor.handPreset === "string") {
|
|
2998
|
+
interactor.handPreset = sourceInteractor.handPreset;
|
|
2999
|
+
}
|
|
3000
|
+
if (typeof sourceInteractor.handColor === "string") {
|
|
3001
|
+
interactor.handColor = sourceInteractor.handColor;
|
|
3002
|
+
}
|
|
3003
|
+
if (typeof sourceInteractor.handOpacity === "number") {
|
|
3004
|
+
interactor.handOpacity = sourceInteractor.handOpacity;
|
|
3005
|
+
}
|
|
3006
|
+
if (typeof sourceInteractor.handEmissiveIntensity === "number") {
|
|
3007
|
+
interactor.handEmissiveIntensity = sourceInteractor.handEmissiveIntensity;
|
|
3008
|
+
}
|
|
3009
|
+
if (typeof sourceInteractor.showRay === "boolean") {
|
|
3010
|
+
interactor.showRay = sourceInteractor.showRay;
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
{
|
|
3015
|
+
const sourceSide = asRecord(
|
|
3016
|
+
values.xrInteractorSideValues.get(sourceEntityId)
|
|
3017
|
+
);
|
|
3018
|
+
if (sourceSide && typeof sourceSide.side === "string") {
|
|
3019
|
+
const existing = world.getComponent(
|
|
3020
|
+
targetEntityId,
|
|
3021
|
+
XRInteractorSideComponent
|
|
3022
|
+
);
|
|
3023
|
+
if (existing) {
|
|
3024
|
+
existing.side = sourceSide.side;
|
|
3025
|
+
} else {
|
|
3026
|
+
world.addComponent(
|
|
3027
|
+
targetEntityId,
|
|
3028
|
+
new XRInteractorSideComponent({
|
|
3029
|
+
side: sourceSide.side
|
|
3030
|
+
})
|
|
3031
|
+
);
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
{
|
|
3036
|
+
const sourceRigOrigin = asRecord(values.xrRigValues.get(sourceEntityId));
|
|
3037
|
+
const rigForOrigin = world.getComponent(targetEntityId, XRRigComponent);
|
|
3038
|
+
if (sourceRigOrigin && rigForOrigin && typeof sourceRigOrigin.trackingOrigin === "string") {
|
|
3039
|
+
rigForOrigin.trackingOrigin = sourceRigOrigin.trackingOrigin;
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
2980
3042
|
{
|
|
2981
3043
|
const imComponent = world.getComponent(targetEntityId, InstancedMeshComponent);
|
|
2982
3044
|
if (imComponent && imComponent.instanceEntityIds.length > 0) {
|
|
@@ -3566,6 +3628,7 @@ var HYDRATABLE_ENTITY_KINDS = /* @__PURE__ */ new Set([
|
|
|
3566
3628
|
"instanceSlot",
|
|
3567
3629
|
"scriptObject",
|
|
3568
3630
|
"xrRig",
|
|
3631
|
+
"xrInteractor",
|
|
3569
3632
|
"teleportArea"
|
|
3570
3633
|
]);
|
|
3571
3634
|
|
|
@@ -6119,6 +6182,9 @@ var _XRInputSystem = class _XRInputSystem {
|
|
|
6119
6182
|
state.hasAxes = false;
|
|
6120
6183
|
state.buttons = [];
|
|
6121
6184
|
}
|
|
6185
|
+
}
|
|
6186
|
+
for (const record of this.records.values()) {
|
|
6187
|
+
const state = record.state;
|
|
6122
6188
|
if (record.pendingSelectStart) {
|
|
6123
6189
|
state.select = true;
|
|
6124
6190
|
state.selectStart = true;
|
|
@@ -6367,6 +6433,10 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
|
|
|
6367
6433
|
/** Curve up to the landing point, for the visual system. Empty when not aiming. */
|
|
6368
6434
|
this.aimCurve = [];
|
|
6369
6435
|
this.landingPoint = null;
|
|
6436
|
+
/** True when the current aim lands somewhere the player may actually stand. */
|
|
6437
|
+
this.aimValid = false;
|
|
6438
|
+
/** Sources currently aiming via thumbstick (hysteresis, so it doesn't chatter). */
|
|
6439
|
+
this.stickAiming = /* @__PURE__ */ new WeakSet();
|
|
6370
6440
|
/** True once we've tried to self-heal camera parenting for this session. */
|
|
6371
6441
|
this.parentingChecked = false;
|
|
6372
6442
|
this.inputSystem = inputSystem;
|
|
@@ -6374,6 +6444,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
|
|
|
6374
6444
|
update(world, deltaTime) {
|
|
6375
6445
|
this.aimCurve = [];
|
|
6376
6446
|
this.landingPoint = null;
|
|
6447
|
+
this.aimValid = false;
|
|
6377
6448
|
if (!world.isXrPresenting()) {
|
|
6378
6449
|
this.parentingChecked = false;
|
|
6379
6450
|
return;
|
|
@@ -6381,6 +6452,7 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
|
|
|
6381
6452
|
if (!this.parentingChecked) {
|
|
6382
6453
|
this.parentingChecked = true;
|
|
6383
6454
|
this.ensureCameraUnderRig(world);
|
|
6455
|
+
this.warnOnIncompleteSetup(world);
|
|
6384
6456
|
}
|
|
6385
6457
|
const rigEntityId = world.query(XRRigComponent, TransformComponent)[0];
|
|
6386
6458
|
if (typeof rigEntityId !== "number") return;
|
|
@@ -6398,6 +6470,26 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
|
|
|
6398
6470
|
this.applySmoothMove(world, rig, rigTransform, inputs, deltaTime);
|
|
6399
6471
|
}
|
|
6400
6472
|
}
|
|
6473
|
+
/**
|
|
6474
|
+
* Name what is missing, once per session.
|
|
6475
|
+
*
|
|
6476
|
+
* Inside a headset there is no console and no inspector, so a scene that
|
|
6477
|
+
* simply cannot move gives the author nothing to go on. These messages are
|
|
6478
|
+
* visible over remote debugging and say exactly which entity to add.
|
|
6479
|
+
*/
|
|
6480
|
+
warnOnIncompleteSetup(world) {
|
|
6481
|
+
if (typeof world.query(XRRigComponent)[0] !== "number") {
|
|
6482
|
+
console.warn(
|
|
6483
|
+
"[XRLocomotion] No XR Rig in this scene \u2014 the player cannot move. Add one via Add Object \u2192 VR \u2192 XR Rig (the scene camera is parented to it automatically)."
|
|
6484
|
+
);
|
|
6485
|
+
return;
|
|
6486
|
+
}
|
|
6487
|
+
if (world.query(VRTeleportAreaComponent).length === 0) {
|
|
6488
|
+
console.warn(
|
|
6489
|
+
"[XRLocomotion] No Teleport Area in this scene \u2014 teleport has nowhere to land. Add one via Add Object \u2192 VR \u2192 Teleport Area, or add a Teleport Area component to an existing floor."
|
|
6490
|
+
);
|
|
6491
|
+
}
|
|
6492
|
+
}
|
|
6401
6493
|
/**
|
|
6402
6494
|
* Guarantee the render camera is a CHILD of the rig.
|
|
6403
6495
|
*
|
|
@@ -6465,29 +6557,60 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
|
|
|
6465
6557
|
}
|
|
6466
6558
|
applyTeleport(world, transform, inputs) {
|
|
6467
6559
|
const targets = this.collectTeleportTargets(world);
|
|
6468
|
-
if (targets.length === 0) return;
|
|
6469
6560
|
for (const input of inputs) {
|
|
6470
|
-
|
|
6561
|
+
const source = input;
|
|
6562
|
+
const stick = this.readStickAim(input, source);
|
|
6563
|
+
const aiming = input.select || stick.aiming;
|
|
6564
|
+
const commit = input.selectEnd || stick.released;
|
|
6565
|
+
if (!aiming && !commit) continue;
|
|
6471
6566
|
const points = sampleTeleportArc(
|
|
6472
6567
|
input.rayOrigin,
|
|
6473
6568
|
input.rayDirection,
|
|
6474
6569
|
this.arcPoints
|
|
6475
6570
|
);
|
|
6476
6571
|
const hit = this.raycastArc(points, targets);
|
|
6477
|
-
|
|
6478
|
-
this.landingPoint = hit.point;
|
|
6479
|
-
this.
|
|
6480
|
-
if (
|
|
6572
|
+
this.aimCurve = hit ? points.slice(0, hit.segmentIndex + 1).concat(hit.point) : points.slice();
|
|
6573
|
+
this.landingPoint = hit ? hit.point : null;
|
|
6574
|
+
this.aimValid = hit !== null;
|
|
6575
|
+
if (commit && hit) {
|
|
6481
6576
|
transform.position.x = hit.point.x;
|
|
6482
6577
|
transform.position.y = hit.point.y;
|
|
6483
6578
|
transform.position.z = hit.point.z;
|
|
6484
6579
|
this.aimCurve = [];
|
|
6485
6580
|
this.landingPoint = null;
|
|
6581
|
+
this.aimValid = false;
|
|
6582
|
+
} else if (commit) {
|
|
6583
|
+
this.aimCurve = [];
|
|
6584
|
+
this.aimValid = false;
|
|
6486
6585
|
}
|
|
6487
6586
|
}
|
|
6488
6587
|
}
|
|
6588
|
+
/**
|
|
6589
|
+
* Thumbstick-forward aiming with hysteresis.
|
|
6590
|
+
*
|
|
6591
|
+
* Engaging at 0.6 and releasing at 0.3 stops a stick resting near the
|
|
6592
|
+
* threshold from flickering the arc on and off — and the release edge is what
|
|
6593
|
+
* commits the teleport, so chatter there would teleport the player randomly.
|
|
6594
|
+
*/
|
|
6595
|
+
readStickAim(input, source) {
|
|
6596
|
+
if (!input.hasAxes || input.axes.length < 4) {
|
|
6597
|
+
return { aiming: false, released: false };
|
|
6598
|
+
}
|
|
6599
|
+
const forward = -(input.axes[3] ?? 0);
|
|
6600
|
+
const wasAiming = this.stickAiming.has(source);
|
|
6601
|
+
if (!wasAiming && forward > 0.6) {
|
|
6602
|
+
this.stickAiming.add(source);
|
|
6603
|
+
return { aiming: true, released: false };
|
|
6604
|
+
}
|
|
6605
|
+
if (wasAiming && forward < 0.3) {
|
|
6606
|
+
this.stickAiming.delete(source);
|
|
6607
|
+
return { aiming: false, released: true };
|
|
6608
|
+
}
|
|
6609
|
+
return { aiming: wasAiming, released: false };
|
|
6610
|
+
}
|
|
6489
6611
|
/** Walk the arc segment-by-segment, returning the first surface hit. */
|
|
6490
6612
|
raycastArc(points, targets) {
|
|
6613
|
+
if (targets.length === 0) return null;
|
|
6491
6614
|
for (let i = 1; i < points.length; i += 1) {
|
|
6492
6615
|
const from = points[i - 1];
|
|
6493
6616
|
const to = points[i];
|
|
@@ -6518,6 +6641,10 @@ var _XRLocomotionSystem = class _XRLocomotionSystem {
|
|
|
6518
6641
|
getAimCurve() {
|
|
6519
6642
|
return this.aimCurve;
|
|
6520
6643
|
}
|
|
6644
|
+
/** True when the aim lands on a valid teleport area. */
|
|
6645
|
+
isAimValid() {
|
|
6646
|
+
return this.aimValid;
|
|
6647
|
+
}
|
|
6521
6648
|
/** Where the arc currently lands, or null when not aiming at a valid area. */
|
|
6522
6649
|
getLandingPoint() {
|
|
6523
6650
|
return this.landingPoint;
|
|
@@ -6560,6 +6687,8 @@ var _XRSessionSystem = class _XRSessionSystem {
|
|
|
6560
6687
|
constructor(inputSystem) {
|
|
6561
6688
|
this.presenting = false;
|
|
6562
6689
|
this.capabilities = NO_XR_CAPABILITIES;
|
|
6690
|
+
/** Y compensation applied when a floor-relative space was requested but not granted. */
|
|
6691
|
+
this.appliedOriginOffset = 0;
|
|
6563
6692
|
this.inputSystem = inputSystem ?? null;
|
|
6564
6693
|
}
|
|
6565
6694
|
update(world) {
|
|
@@ -6583,11 +6712,59 @@ var _XRSessionSystem = class _XRSessionSystem {
|
|
|
6583
6712
|
if (session && this.inputSystem) {
|
|
6584
6713
|
this.inputSystem.attachSession(session);
|
|
6585
6714
|
}
|
|
6715
|
+
this.applyTrackingOrigin(world, session ?? null);
|
|
6586
6716
|
this.forEachBehaviour(world, (behaviour) => {
|
|
6587
6717
|
behaviour.onXRSessionStart(this.capabilities);
|
|
6588
6718
|
});
|
|
6589
6719
|
}
|
|
6720
|
+
/**
|
|
6721
|
+
* Apply the rig's authored tracking origin, and compensate when the device
|
|
6722
|
+
* cannot honour it.
|
|
6723
|
+
*
|
|
6724
|
+
* `floor` (`local-floor`) puts Y=0 on the user's real floor, which is what a
|
|
6725
|
+
* scene authored standing on the ground expects. `eye` (`local`) puts Y=0 at
|
|
6726
|
+
* the headset, for seated experiences.
|
|
6727
|
+
*
|
|
6728
|
+
* The compensation matters: `local-floor` is only ever REQUESTED as an
|
|
6729
|
+
* optional feature (requiring it would make `requestSession` reject outright
|
|
6730
|
+
* on devices that lack it). When it isn't granted, the runtime silently falls
|
|
6731
|
+
* back to `local` — the origin jumps to head height and a floor-authored
|
|
6732
|
+
* scene swallows the user, which is exactly the "I'm standing under the
|
|
6733
|
+
* building" symptom. Offsetting the rig down by the eye height restores the
|
|
6734
|
+
* intended floor relationship instead of leaving it broken.
|
|
6735
|
+
*/
|
|
6736
|
+
applyTrackingOrigin(world, session) {
|
|
6737
|
+
const rigEntityId = world.query(XRRigComponent, TransformComponent)[0];
|
|
6738
|
+
if (typeof rigEntityId !== "number") return;
|
|
6739
|
+
const rig = world.getComponent(rigEntityId, XRRigComponent);
|
|
6740
|
+
const transform = world.getComponent(rigEntityId, TransformComponent);
|
|
6741
|
+
if (!rig || !transform) return;
|
|
6742
|
+
const renderer = world.getRenderer();
|
|
6743
|
+
const wantsFloor = rig.trackingOrigin === "floor";
|
|
6744
|
+
try {
|
|
6745
|
+
renderer.xr.setReferenceSpaceType(wantsFloor ? "local-floor" : "local");
|
|
6746
|
+
} catch {
|
|
6747
|
+
}
|
|
6748
|
+
const granted = session?.enabledFeatures;
|
|
6749
|
+
const floorGranted = Array.isArray(granted) ? granted.includes("local-floor") : (
|
|
6750
|
+
// No report at all: trust the request, since a wrong offset is worse
|
|
6751
|
+
// than none on devices that did honour it.
|
|
6752
|
+
true
|
|
6753
|
+
);
|
|
6754
|
+
this.appliedOriginOffset = wantsFloor && !floorGranted ? rig.fallbackEyeHeight : 0;
|
|
6755
|
+
if (this.appliedOriginOffset !== 0) {
|
|
6756
|
+
transform.position.y -= this.appliedOriginOffset;
|
|
6757
|
+
}
|
|
6758
|
+
}
|
|
6590
6759
|
handleSessionEnd(world) {
|
|
6760
|
+
if (this.appliedOriginOffset !== 0) {
|
|
6761
|
+
const rigEntityId = world.query(XRRigComponent, TransformComponent)[0];
|
|
6762
|
+
if (typeof rigEntityId === "number") {
|
|
6763
|
+
const transform = world.getComponent(rigEntityId, TransformComponent);
|
|
6764
|
+
if (transform) transform.position.y += this.appliedOriginOffset;
|
|
6765
|
+
}
|
|
6766
|
+
this.appliedOriginOffset = 0;
|
|
6767
|
+
}
|
|
6591
6768
|
this.capabilities = NO_XR_CAPABILITIES;
|
|
6592
6769
|
this.inputSystem?.detachSession();
|
|
6593
6770
|
this.forEachBehaviour(world, (behaviour) => {
|
|
@@ -6681,17 +6858,74 @@ var _VRTeleportAreaSystem = class _VRTeleportAreaSystem {
|
|
|
6681
6858
|
};
|
|
6682
6859
|
__name(_VRTeleportAreaSystem, "VRTeleportAreaSystem");
|
|
6683
6860
|
var VRTeleportAreaSystem = _VRTeleportAreaSystem;
|
|
6861
|
+
function createHandMaterial(preset, options) {
|
|
6862
|
+
const color = new THREE7.Color(options.color);
|
|
6863
|
+
switch (preset) {
|
|
6864
|
+
case "ghost":
|
|
6865
|
+
return new THREE7.MeshBasicMaterial({
|
|
6866
|
+
color,
|
|
6867
|
+
transparent: true,
|
|
6868
|
+
opacity: Math.min(1, Math.max(0.05, options.opacity * 0.45)),
|
|
6869
|
+
depthWrite: false,
|
|
6870
|
+
side: THREE7.DoubleSide
|
|
6871
|
+
});
|
|
6872
|
+
case "neon":
|
|
6873
|
+
return new THREE7.MeshStandardMaterial({
|
|
6874
|
+
color,
|
|
6875
|
+
emissive: color,
|
|
6876
|
+
emissiveIntensity: Math.max(0.5, options.emissiveIntensity || 2),
|
|
6877
|
+
roughness: 0.35,
|
|
6878
|
+
metalness: 0,
|
|
6879
|
+
transparent: options.opacity < 1,
|
|
6880
|
+
opacity: options.opacity
|
|
6881
|
+
});
|
|
6882
|
+
case "skeleton":
|
|
6883
|
+
return new THREE7.MeshBasicMaterial({
|
|
6884
|
+
color,
|
|
6885
|
+
wireframe: true,
|
|
6886
|
+
transparent: true,
|
|
6887
|
+
opacity: options.opacity
|
|
6888
|
+
});
|
|
6889
|
+
case "custom":
|
|
6890
|
+
case "default":
|
|
6891
|
+
return new THREE7.MeshStandardMaterial({
|
|
6892
|
+
color,
|
|
6893
|
+
roughness: 0.85,
|
|
6894
|
+
metalness: 0,
|
|
6895
|
+
emissive: color,
|
|
6896
|
+
emissiveIntensity: Math.max(0, options.emissiveIntensity),
|
|
6897
|
+
transparent: options.opacity < 1,
|
|
6898
|
+
opacity: options.opacity,
|
|
6899
|
+
side: THREE7.DoubleSide
|
|
6900
|
+
});
|
|
6901
|
+
default: {
|
|
6902
|
+
return new THREE7.MeshStandardMaterial({ color });
|
|
6903
|
+
}
|
|
6904
|
+
}
|
|
6905
|
+
}
|
|
6906
|
+
__name(createHandMaterial, "createHandMaterial");
|
|
6907
|
+
function applyHandMaterial(root, material) {
|
|
6908
|
+
root.traverse((child) => {
|
|
6909
|
+
const mesh = child;
|
|
6910
|
+
if (!mesh.isMesh) return;
|
|
6911
|
+
mesh.material = material;
|
|
6912
|
+
});
|
|
6913
|
+
}
|
|
6914
|
+
__name(applyHandMaterial, "applyHandMaterial");
|
|
6915
|
+
var SLOTS = [
|
|
6916
|
+
{ index: 0, side: "left" },
|
|
6917
|
+
{ index: 1, side: "right" }
|
|
6918
|
+
];
|
|
6684
6919
|
var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
6685
6920
|
constructor(options) {
|
|
6686
6921
|
this.controllerModelFactory = new XRControllerModelFactory();
|
|
6687
6922
|
this.handModelFactory = new XRHandModelFactory();
|
|
6688
6923
|
this.group = new THREE7.Group();
|
|
6689
|
-
this.
|
|
6924
|
+
this.slots = /* @__PURE__ */ new Map();
|
|
6690
6925
|
this.attachedTo = null;
|
|
6691
|
-
/**
|
|
6692
|
-
this.
|
|
6693
|
-
this.
|
|
6694
|
-
this.slots = options?.slots ?? 2;
|
|
6926
|
+
/** Last applied preset signature, so materials rebuild only on real change. */
|
|
6927
|
+
this.handStyleSignature = "";
|
|
6928
|
+
this.handMaterial = null;
|
|
6695
6929
|
this.interactionSystem = options?.interactionSystem ?? null;
|
|
6696
6930
|
this.group.name = "XRControllerVisuals";
|
|
6697
6931
|
this.group.userData.ecsPreviewHidden = true;
|
|
@@ -6700,39 +6934,111 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
6700
6934
|
const renderer = world.getRenderer();
|
|
6701
6935
|
if (!renderer.xr?.enabled) return;
|
|
6702
6936
|
this.ensureAttached(world);
|
|
6703
|
-
this.
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6937
|
+
this.ensureSlots(world);
|
|
6938
|
+
const interactor = this.resolveInteractor(world);
|
|
6939
|
+
const type = interactor?.interactorType ?? "both";
|
|
6940
|
+
const showControllers = type === "controllers" || type === "both";
|
|
6941
|
+
const showHands = type === "hands" || type === "both";
|
|
6942
|
+
this.syncHandMaterial(interactor);
|
|
6943
|
+
for (const { index, side } of SLOTS) {
|
|
6944
|
+
const visuals = this.slots.get(index);
|
|
6945
|
+
if (!visuals) continue;
|
|
6946
|
+
visuals.controllerModel.visible = showControllers;
|
|
6947
|
+
visuals.handModel.visible = showHands;
|
|
6948
|
+
visuals.ray.visible = this.shouldShowRay(interactor);
|
|
6949
|
+
if (showHands && this.handMaterial) {
|
|
6950
|
+
applyHandMaterial(visuals.handModel, this.handMaterial);
|
|
6951
|
+
}
|
|
6952
|
+
this.syncCustomContent(world, visuals, side);
|
|
6953
|
+
}
|
|
6954
|
+
}
|
|
6955
|
+
/** The scene's interactor config, if one was authored. */
|
|
6956
|
+
resolveInteractor(world) {
|
|
6957
|
+
const entityId = world.query(XRInteractorComponent)[0];
|
|
6958
|
+
if (typeof entityId !== "number") return null;
|
|
6959
|
+
return world.getComponent(entityId, XRInteractorComponent) ?? null;
|
|
6960
|
+
}
|
|
6961
|
+
/**
|
|
6962
|
+
* Re-parent the author's left/right interactor content onto the tracked grip
|
|
6963
|
+
* space so it follows the hand.
|
|
6964
|
+
*
|
|
6965
|
+
* `ObjectManagementSystem` reconciles ECS objects back under their ParentId
|
|
6966
|
+
* every frame, so this re-attach has to be re-asserted — the same coexistence
|
|
6967
|
+
* dance the AR anchor system performs.
|
|
6968
|
+
*/
|
|
6969
|
+
syncCustomContent(world, visuals, side) {
|
|
6970
|
+
let content = null;
|
|
6971
|
+
for (const entityId of world.query(
|
|
6972
|
+
XRInteractorSideComponent,
|
|
6973
|
+
Object3DRef
|
|
6974
|
+
)) {
|
|
6975
|
+
const slot = world.getComponent(entityId, XRInteractorSideComponent);
|
|
6976
|
+
if (slot?.side !== side) continue;
|
|
6977
|
+
content = world.getComponent(entityId, Object3DRef)?.object ?? null;
|
|
6978
|
+
break;
|
|
6979
|
+
}
|
|
6980
|
+
if (!content) {
|
|
6981
|
+
visuals.attachedCustom = null;
|
|
6982
|
+
return;
|
|
6983
|
+
}
|
|
6984
|
+
if (content.parent !== visuals.grip) {
|
|
6985
|
+
visuals.grip.add(content);
|
|
6986
|
+
}
|
|
6987
|
+
visuals.attachedCustom = content;
|
|
6988
|
+
}
|
|
6989
|
+
/** Rebuild the hand material only when the authored style actually changes. */
|
|
6990
|
+
syncHandMaterial(interactor) {
|
|
6991
|
+
const preset = interactor?.handPreset ?? "default";
|
|
6992
|
+
const color = interactor?.handColor ?? "#e8b48a";
|
|
6993
|
+
const opacity = interactor?.handOpacity ?? 1;
|
|
6994
|
+
const emissive = interactor?.handEmissiveIntensity ?? 0;
|
|
6995
|
+
const signature = `${preset}:${color}:${opacity}:${emissive}`;
|
|
6996
|
+
if (signature === this.handStyleSignature && this.handMaterial) return;
|
|
6997
|
+
this.handStyleSignature = signature;
|
|
6998
|
+
this.handMaterial?.dispose();
|
|
6999
|
+
this.handMaterial = createHandMaterial(preset, {
|
|
7000
|
+
color,
|
|
7001
|
+
opacity,
|
|
7002
|
+
emissiveIntensity: emissive
|
|
7003
|
+
});
|
|
7004
|
+
}
|
|
7005
|
+
/**
|
|
7006
|
+
* The ray is meaningful only when it points at something. Authors can turn it
|
|
7007
|
+
* off entirely; otherwise it appears on hover/grab so it isn't permanent
|
|
7008
|
+
* clutter implying the whole scene is clickable.
|
|
7009
|
+
*/
|
|
7010
|
+
shouldShowRay(interactor) {
|
|
7011
|
+
if (interactor && !interactor.showRay) return false;
|
|
7012
|
+
if (!this.interactionSystem) return true;
|
|
7013
|
+
return this.interactionSystem.getHoveredEntityId() !== null || this.interactionSystem.isGrabbing();
|
|
7014
|
+
}
|
|
7015
|
+
/** Lazily build per-slot visuals; the device reports profiles late. */
|
|
7016
|
+
ensureSlots(world) {
|
|
7017
|
+
const renderer = world.getRenderer();
|
|
7018
|
+
for (const { index } of SLOTS) {
|
|
7019
|
+
if (this.slots.has(index)) continue;
|
|
6707
7020
|
const controller = renderer.xr.getController(index);
|
|
6708
7021
|
const grip = renderer.xr.getControllerGrip(index);
|
|
6709
7022
|
const hand = renderer.xr.getHand(index);
|
|
6710
7023
|
if (!controller || !grip || !hand) continue;
|
|
6711
7024
|
const ray = this.createRay();
|
|
6712
|
-
this.rays.push(ray);
|
|
6713
7025
|
controller.add(ray);
|
|
6714
|
-
this.
|
|
6715
|
-
grip.add(
|
|
6716
|
-
this.
|
|
6717
|
-
hand.add(
|
|
6718
|
-
this.group.add(hand);
|
|
6719
|
-
this.
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
7026
|
+
const controllerModel = this.controllerModelFactory.createControllerModel(grip);
|
|
7027
|
+
grip.add(controllerModel);
|
|
7028
|
+
const handModel = this.handModelFactory.createHandModel(hand, "mesh");
|
|
7029
|
+
hand.add(handModel);
|
|
7030
|
+
this.group.add(controller, grip, hand);
|
|
7031
|
+
this.slots.set(index, {
|
|
7032
|
+
controller,
|
|
7033
|
+
grip,
|
|
7034
|
+
hand,
|
|
7035
|
+
ray,
|
|
7036
|
+
controllerModel,
|
|
7037
|
+
handModel,
|
|
7038
|
+
attachedCustom: null
|
|
7039
|
+
});
|
|
6723
7040
|
}
|
|
6724
7041
|
}
|
|
6725
|
-
/**
|
|
6726
|
-
* Show the aim ray only when it is meaningful: hovering something
|
|
6727
|
-
* interactive, or mid-grab. A permanently-drawn ray is visual noise, and it
|
|
6728
|
-
* implies everything is clickable when most of the scene is not. Teleport
|
|
6729
|
-
* aiming has its own arc, so the straight ray stays hidden for that.
|
|
6730
|
-
*/
|
|
6731
|
-
updateRayVisibility() {
|
|
6732
|
-
if (!this.interactionSystem) return;
|
|
6733
|
-
const active = this.interactionSystem.getHoveredEntityId() !== null || this.interactionSystem.isGrabbing();
|
|
6734
|
-
for (const ray of this.rays) ray.visible = active;
|
|
6735
|
-
}
|
|
6736
7042
|
/**
|
|
6737
7043
|
* Parent the visuals to the XR rig when there is one, so locomotion moves the
|
|
6738
7044
|
* hands with the player. Falls back to the scene root.
|
|
@@ -6758,7 +7064,7 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
6758
7064
|
const line = new THREE7.Line(geometry, material);
|
|
6759
7065
|
line.name = "XRPointerRay";
|
|
6760
7066
|
line.renderOrder = 999;
|
|
6761
|
-
line.visible =
|
|
7067
|
+
line.visible = false;
|
|
6762
7068
|
return line;
|
|
6763
7069
|
}
|
|
6764
7070
|
dispose() {
|
|
@@ -6774,9 +7080,10 @@ var _XRControllerVisualSystem = class _XRControllerVisualSystem {
|
|
|
6774
7080
|
}
|
|
6775
7081
|
});
|
|
6776
7082
|
this.group.clear();
|
|
6777
|
-
this.
|
|
6778
|
-
this.
|
|
6779
|
-
this.
|
|
7083
|
+
this.slots.clear();
|
|
7084
|
+
this.handMaterial?.dispose();
|
|
7085
|
+
this.handMaterial = null;
|
|
7086
|
+
this.handStyleSignature = "";
|
|
6780
7087
|
this.attachedTo = null;
|
|
6781
7088
|
}
|
|
6782
7089
|
};
|
|
@@ -6784,6 +7091,7 @@ __name(_XRControllerVisualSystem, "XRControllerVisualSystem");
|
|
|
6784
7091
|
var XRControllerVisualSystem = _XRControllerVisualSystem;
|
|
6785
7092
|
var MARKER_RADIUS = 0.28;
|
|
6786
7093
|
var ACCENT = new THREE7.Color("#4da3ff");
|
|
7094
|
+
var BLOCKED = new THREE7.Color("#ff5a5a");
|
|
6787
7095
|
var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
6788
7096
|
constructor(locomotionSystem) {
|
|
6789
7097
|
this.group = new THREE7.Group();
|
|
@@ -6814,16 +7122,22 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
6814
7122
|
}
|
|
6815
7123
|
const curve = this.locomotionSystem.getAimCurve();
|
|
6816
7124
|
const landing = this.locomotionSystem.getLandingPoint();
|
|
6817
|
-
|
|
7125
|
+
const valid = this.locomotionSystem.isAimValid();
|
|
7126
|
+
if (curve.length < 2) {
|
|
6818
7127
|
this.setVisible(false);
|
|
6819
7128
|
return;
|
|
6820
7129
|
}
|
|
6821
|
-
this.updateArcGeometry(curve);
|
|
6822
|
-
|
|
6823
|
-
|
|
7130
|
+
this.updateArcGeometry(curve, valid ? ACCENT : BLOCKED);
|
|
7131
|
+
if (valid && landing) {
|
|
7132
|
+
this.marker.position.copy(landing);
|
|
7133
|
+
this.marker.position.y += 0.01;
|
|
7134
|
+
this.marker.visible = true;
|
|
7135
|
+
} else {
|
|
7136
|
+
this.marker.visible = false;
|
|
7137
|
+
}
|
|
6824
7138
|
this.setVisible(true);
|
|
6825
7139
|
}
|
|
6826
|
-
updateArcGeometry(curve) {
|
|
7140
|
+
updateArcGeometry(curve, tint) {
|
|
6827
7141
|
const count = curve.length;
|
|
6828
7142
|
const positions = new Float32Array(count * 3);
|
|
6829
7143
|
const colors = new Float32Array(count * 3);
|
|
@@ -6834,9 +7148,9 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
6834
7148
|
positions[i * 3 + 2] = point.z;
|
|
6835
7149
|
const t = count > 1 ? i / (count - 1) : 0;
|
|
6836
7150
|
const fade = 1 - t * 0.75;
|
|
6837
|
-
colors[i * 3] =
|
|
6838
|
-
colors[i * 3 + 1] =
|
|
6839
|
-
colors[i * 3 + 2] =
|
|
7151
|
+
colors[i * 3] = tint.r * fade;
|
|
7152
|
+
colors[i * 3 + 1] = tint.g * fade;
|
|
7153
|
+
colors[i * 3 + 2] = tint.b * fade;
|
|
6840
7154
|
}
|
|
6841
7155
|
this.arcGeometry.setAttribute(
|
|
6842
7156
|
"position",
|
|
@@ -6898,6 +7212,6 @@ var _XRTeleportVisualSystem = class _XRTeleportVisualSystem {
|
|
|
6898
7212
|
__name(_XRTeleportVisualSystem, "XRTeleportVisualSystem");
|
|
6899
7213
|
var XRTeleportVisualSystem = _XRTeleportVisualSystem;
|
|
6900
7214
|
|
|
6901
|
-
export { ADDED_NODE_MARKER_COMPONENT, ARC_GRAVITY, ARC_MAX_TIME, ARC_SPEED, ARC_STEPS, AnimationSystem, AudioSystem, Behaviour, CameraSyncSystem, EnvironmentSyncSystem, HYDRATABLE_ENTITY_KINDS, InputSystem, InstancedMeshSystem, KeyboardKeys, LightSyncSystem, MaterialSyncSystem, MeshGeometrySystem, NODE_KEY_SEPARATOR, NO_XR_CAPABILITIES, OVERRIDE_DIFF_EXCLUDED_COMPONENTS, OVERRIDE_ROOT_EXCLUDED_COMPONENTS, ObjectVisibilitySystem, PREFAB_FILE_VERSION, PREFAB_FILE_VERSION_NESTED, PhysicsSyncSystem, PostprocessingSyncSystem, RenderSystem, SCRIPT_OBJECT_ROOT_FLAG, ScriptBehaviourSystem, ScriptObject, ScriptObjectSystem, TransformSyncSystem, VRTeleportAreaSystem, VideoSystem, XRControllerVisualSystem, XRInputSystem, XRInteractionSystem, XRLocomotionSystem, XRSessionSystem, XRTeleportVisualSystem, arcGroundCrossing, buildComponentValueMaps, buildNodeKeyMapsFromSnapshot, buildNodeMapsFromSnapshot, canonicalizeComponentValue, clearPrefabCache, collectDiffPaths, collectEntitySubtree, collectSnapshotSubtreeIds, computeInstanceOverrides, decanonicalizeComponentValue, despawnPrefab, encodeOverride, findSnapshotRootEntityIds, findTopLevelNestedRegions, groupOverridePaths, hydrateWorldFromSnapshot, hydrateWorldFromSnapshotDetailed, indexSnapshotByEntity, instantiateSubtree, loadPrefab, mergeComponentValue, parseOverride, parsePrefabAsset, prefabFileVersionFor, readXrCapabilities, restoreComponentState, restorePostCreateComponents, sampleTeleportArc, setPrefabAssetUrlResolver, spawnPrefab };
|
|
6902
|
-
//# sourceMappingURL=chunk-
|
|
6903
|
-
//# sourceMappingURL=chunk-
|
|
7215
|
+
export { ADDED_NODE_MARKER_COMPONENT, ARC_GRAVITY, ARC_MAX_TIME, ARC_SPEED, ARC_STEPS, AnimationSystem, AudioSystem, Behaviour, CameraSyncSystem, EnvironmentSyncSystem, HYDRATABLE_ENTITY_KINDS, InputSystem, InstancedMeshSystem, KeyboardKeys, LightSyncSystem, MaterialSyncSystem, MeshGeometrySystem, NODE_KEY_SEPARATOR, NO_XR_CAPABILITIES, OVERRIDE_DIFF_EXCLUDED_COMPONENTS, OVERRIDE_ROOT_EXCLUDED_COMPONENTS, ObjectVisibilitySystem, PREFAB_FILE_VERSION, PREFAB_FILE_VERSION_NESTED, PhysicsSyncSystem, PostprocessingSyncSystem, RenderSystem, SCRIPT_OBJECT_ROOT_FLAG, ScriptBehaviourSystem, ScriptObject, ScriptObjectSystem, TransformSyncSystem, VRTeleportAreaSystem, VideoSystem, XRControllerVisualSystem, XRInputSystem, XRInteractionSystem, XRLocomotionSystem, XRSessionSystem, XRTeleportVisualSystem, applyHandMaterial, arcGroundCrossing, buildComponentValueMaps, buildNodeKeyMapsFromSnapshot, buildNodeMapsFromSnapshot, canonicalizeComponentValue, clearPrefabCache, collectDiffPaths, collectEntitySubtree, collectSnapshotSubtreeIds, computeInstanceOverrides, createHandMaterial, decanonicalizeComponentValue, despawnPrefab, encodeOverride, findSnapshotRootEntityIds, findTopLevelNestedRegions, groupOverridePaths, hydrateWorldFromSnapshot, hydrateWorldFromSnapshotDetailed, indexSnapshotByEntity, instantiateSubtree, loadPrefab, mergeComponentValue, parseOverride, parsePrefabAsset, prefabFileVersionFor, readXrCapabilities, restoreComponentState, restorePostCreateComponents, sampleTeleportArc, setPrefabAssetUrlResolver, spawnPrefab };
|
|
7216
|
+
//# sourceMappingURL=chunk-O6FJA4XW.js.map
|
|
7217
|
+
//# sourceMappingURL=chunk-O6FJA4XW.js.map
|