@threlte/xr 0.0.11 → 0.0.13
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/components/ARButton.svelte +1 -1
- package/dist/components/Controller.svelte +69 -79
- package/dist/components/Controller.svelte.d.ts +4 -0
- package/dist/components/Hand.svelte +25 -58
- package/dist/components/Hand.svelte.d.ts +1 -0
- package/dist/components/Headset.svelte +4 -7
- package/dist/components/XR.svelte +46 -52
- package/dist/components/XRButton.svelte +2 -2
- package/dist/components/internal/Cursor.svelte +51 -0
- package/dist/components/internal/Cursor.svelte.d.ts +19 -0
- package/dist/components/internal/PointerCursor.svelte +46 -0
- package/dist/components/internal/PointerCursor.svelte.d.ts +18 -0
- package/dist/components/internal/ScenePortal.svelte +10 -0
- package/dist/components/internal/ScenePortal.svelte.d.ts +16 -0
- package/dist/components/internal/ShortRay.svelte +45 -0
- package/dist/components/{ShortRay.svelte.d.ts → internal/ShortRay.svelte.d.ts} +4 -2
- package/dist/components/internal/TeleportCursor.svelte +51 -0
- package/dist/components/internal/TeleportCursor.svelte.d.ts +18 -0
- package/dist/components/internal/TeleportRay.svelte +71 -0
- package/dist/components/internal/TeleportRay.svelte.d.ts +20 -0
- package/dist/hooks/useController.d.ts +0 -4
- package/dist/hooks/useController.js +2 -15
- package/dist/hooks/useHand.js +2 -0
- package/dist/hooks/useHandJoint.d.ts +2 -2
- package/dist/hooks/useHeadset.d.ts +2 -1
- package/dist/hooks/useHeadset.js +1 -1
- package/dist/hooks/useHitTest.d.ts +2 -2
- package/dist/hooks/useHitTest.js +16 -6
- package/dist/hooks/useTeleport.d.ts +2 -2
- package/dist/hooks/useTeleport.js +2 -2
- package/dist/index.d.ts +10 -3
- package/dist/index.js +13 -2
- package/dist/internal/setupControllers.d.ts +1 -0
- package/dist/internal/setupControllers.js +69 -0
- package/dist/internal/setupHands.d.ts +1 -0
- package/dist/internal/setupHands.js +63 -0
- package/dist/internal/setupHeadset.d.ts +3 -0
- package/dist/internal/{headset.js → setupHeadset.js} +3 -4
- package/dist/internal/setupRaf.d.ts +1 -0
- package/dist/internal/{updateRaf.js → setupRaf.js} +2 -2
- package/dist/internal/stores.d.ts +46 -5
- package/dist/internal/stores.js +36 -4
- package/dist/internal/useFixed.d.ts +11 -0
- package/dist/internal/useFixed.js +17 -0
- package/dist/internal/useHandTrackingState.js +1 -1
- package/dist/lib/toggleXRSession.js +3 -3
- package/dist/plugins/pointerControls/compute.d.ts +3 -0
- package/dist/plugins/pointerControls/compute.js +14 -0
- package/dist/plugins/pointerControls/context.d.ts +12 -0
- package/dist/plugins/pointerControls/context.js +27 -0
- package/dist/plugins/pointerControls/hook.d.ts +5 -0
- package/dist/plugins/pointerControls/hook.js +24 -0
- package/dist/plugins/pointerControls/index.d.ts +27 -0
- package/dist/plugins/pointerControls/index.js +54 -0
- package/dist/plugins/pointerControls/plugin.d.ts +1 -0
- package/dist/plugins/pointerControls/plugin.js +28 -0
- package/dist/plugins/pointerControls/setup.d.ts +2 -0
- package/dist/plugins/pointerControls/setup.js +203 -0
- package/dist/plugins/pointerControls/types.d.ts +62 -0
- package/dist/plugins/pointerControls/types.js +11 -0
- package/dist/plugins/pointerControls/useComponentEventHandlers.d.ts +4 -0
- package/dist/plugins/pointerControls/useComponentEventHandlers.js +15 -0
- package/dist/plugins/teleportControls/compute.d.ts +3 -0
- package/dist/plugins/teleportControls/compute.js +14 -0
- package/dist/plugins/teleportControls/context.d.ts +21 -0
- package/dist/plugins/teleportControls/context.js +18 -0
- package/dist/plugins/teleportControls/hook.d.ts +7 -0
- package/dist/plugins/teleportControls/hook.js +40 -0
- package/dist/plugins/teleportControls/index.d.ts +19 -0
- package/dist/plugins/teleportControls/index.js +54 -0
- package/dist/plugins/teleportControls/plugin.d.ts +4 -0
- package/dist/plugins/teleportControls/plugin.js +54 -0
- package/dist/plugins/teleportControls/setup.d.ts +2 -0
- package/dist/plugins/teleportControls/setup.js +62 -0
- package/dist/types.d.ts +10 -8
- package/package.json +4 -4
- package/dist/components/Ray.svelte +0 -23
- package/dist/components/Ray.svelte.d.ts +0 -18
- package/dist/components/ShortRay.svelte +0 -32
- package/dist/components/TeleportControls.svelte +0 -136
- package/dist/components/TeleportControls.svelte.d.ts +0 -54
- package/dist/hooks/index.d.ts +0 -7
- package/dist/hooks/index.js +0 -7
- package/dist/internal/headset.d.ts +0 -3
- package/dist/internal/updateRaf.d.ts +0 -1
- package/dist/plugins/teleportPlugin.d.ts +0 -1
- package/dist/plugins/teleportPlugin.js +0 -41
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: Record<string, never>;
|
|
4
|
+
events: {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
};
|
|
7
|
+
slots: {
|
|
8
|
+
default: {};
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export type ScenePortalProps = typeof __propDef.props;
|
|
12
|
+
export type ScenePortalEvents = typeof __propDef.events;
|
|
13
|
+
export type ScenePortalSlots = typeof __propDef.slots;
|
|
14
|
+
export default class ScenePortal extends SvelteComponent<ScenePortalProps, ScenePortalEvents, ScenePortalSlots> {
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script>import { T } from "@threlte/core";
|
|
2
|
+
import { pointerState, teleportState, teleportIntersection } from "../../internal/stores";
|
|
3
|
+
export let handedness;
|
|
4
|
+
$:
|
|
5
|
+
hovering = $teleportState[handedness].hovering;
|
|
6
|
+
$:
|
|
7
|
+
intersection = teleportIntersection[handedness];
|
|
8
|
+
$:
|
|
9
|
+
visible = $pointerState[handedness].enabled || hovering && $intersection === void 0;
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<T.Group {visible}>
|
|
13
|
+
<slot>
|
|
14
|
+
<T.Mesh
|
|
15
|
+
rotation.x={-Math.PI / 2}
|
|
16
|
+
position.z={-0.1}
|
|
17
|
+
>
|
|
18
|
+
<T.CylinderGeometry
|
|
19
|
+
args={[0.002, 0.002, 0.2, 16, 1, false]}
|
|
20
|
+
/>
|
|
21
|
+
<T.RawShaderMaterial
|
|
22
|
+
transparent
|
|
23
|
+
vertexShader={`
|
|
24
|
+
uniform mat4 modelViewMatrix;
|
|
25
|
+
uniform mat4 projectionMatrix;
|
|
26
|
+
attribute vec2 uv;
|
|
27
|
+
attribute vec3 position;
|
|
28
|
+
varying vec2 vUv;
|
|
29
|
+
void main() {
|
|
30
|
+
vUv = uv;
|
|
31
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
32
|
+
}
|
|
33
|
+
`}
|
|
34
|
+
fragmentShader={`
|
|
35
|
+
precision mediump float;
|
|
36
|
+
varying vec2 vUv;
|
|
37
|
+
void main() {
|
|
38
|
+
gl_FragColor = vec4(1.0, 1.0, 1.0, pow(vUv.y - 1.0, 2.0));
|
|
39
|
+
}
|
|
40
|
+
`}
|
|
41
|
+
/>
|
|
42
|
+
</T.Mesh>
|
|
43
|
+
</slot>
|
|
44
|
+
</T.Group>
|
|
45
|
+
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
2
|
declare const __propDef: {
|
|
3
3
|
props: {
|
|
4
|
-
|
|
4
|
+
handedness: 'left' | 'right';
|
|
5
5
|
};
|
|
6
6
|
events: {
|
|
7
7
|
[evt: string]: CustomEvent<any>;
|
|
8
8
|
};
|
|
9
|
-
slots: {
|
|
9
|
+
slots: {
|
|
10
|
+
default: {};
|
|
11
|
+
};
|
|
10
12
|
};
|
|
11
13
|
export type ShortRayProps = typeof __propDef.props;
|
|
12
14
|
export type ShortRayEvents = typeof __propDef.events;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script>import { spring } from "svelte/motion";
|
|
2
|
+
import { Group, Matrix3, Vector3 } from "three";
|
|
3
|
+
import { T, useFrame } from "@threlte/core";
|
|
4
|
+
import { teleportIntersection } from "../../internal/stores";
|
|
5
|
+
import Cursor from "./Cursor.svelte";
|
|
6
|
+
export let handedness;
|
|
7
|
+
const ref = new Group();
|
|
8
|
+
const vec3 = new Vector3();
|
|
9
|
+
const normalMatrix = new Matrix3();
|
|
10
|
+
const worldNormal = new Vector3();
|
|
11
|
+
$:
|
|
12
|
+
intersection = teleportIntersection[handedness];
|
|
13
|
+
const { start, stop } = useFrame(
|
|
14
|
+
() => {
|
|
15
|
+
if (intersection.current === void 0)
|
|
16
|
+
return;
|
|
17
|
+
const { point, face, object } = intersection.current;
|
|
18
|
+
ref.position.lerp(point, 0.4);
|
|
19
|
+
if (face) {
|
|
20
|
+
normalMatrix.getNormalMatrix(object.matrixWorld);
|
|
21
|
+
worldNormal.copy(face.normal).applyMatrix3(normalMatrix).normalize();
|
|
22
|
+
ref.lookAt(vec3.addVectors(point, worldNormal));
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
autostart: false
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
const size = spring(0.1, { stiffness: 0.2 });
|
|
30
|
+
$:
|
|
31
|
+
if ($intersection === void 0) {
|
|
32
|
+
size.set(0.1);
|
|
33
|
+
stop();
|
|
34
|
+
} else {
|
|
35
|
+
size.set(1);
|
|
36
|
+
ref.position.copy($intersection.point);
|
|
37
|
+
start();
|
|
38
|
+
}
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<T
|
|
42
|
+
is={ref}
|
|
43
|
+
visible={$intersection !== undefined}
|
|
44
|
+
>
|
|
45
|
+
<slot>
|
|
46
|
+
<Cursor
|
|
47
|
+
size={$size}
|
|
48
|
+
thickness={0.015}
|
|
49
|
+
/>
|
|
50
|
+
</slot>
|
|
51
|
+
</T>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
declare const __propDef: {
|
|
3
|
+
props: {
|
|
4
|
+
handedness: 'left' | 'right';
|
|
5
|
+
};
|
|
6
|
+
events: {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
};
|
|
9
|
+
slots: {
|
|
10
|
+
default: {};
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export type TeleportCursorProps = typeof __propDef.props;
|
|
14
|
+
export type TeleportCursorEvents = typeof __propDef.events;
|
|
15
|
+
export type TeleportCursorSlots = typeof __propDef.slots;
|
|
16
|
+
export default class TeleportCursor extends SvelteComponent<TeleportCursorProps, TeleportCursorEvents, TeleportCursorSlots> {
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script>import { Vector3, QuadraticBezierCurve3, Vector2 } from "three";
|
|
2
|
+
import { Line2 } from "three/examples/jsm/lines/Line2";
|
|
3
|
+
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry";
|
|
4
|
+
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial";
|
|
5
|
+
import { T, useFrame } from "@threlte/core";
|
|
6
|
+
import { teleportIntersection } from "../../internal/stores";
|
|
7
|
+
export let handedness;
|
|
8
|
+
export let targetRay;
|
|
9
|
+
let lineGeometry = new LineGeometry();
|
|
10
|
+
const rayStart = new Vector3();
|
|
11
|
+
const rayMidpoint = new Vector3();
|
|
12
|
+
const curve = new QuadraticBezierCurve3();
|
|
13
|
+
const rayDivisions = 40;
|
|
14
|
+
const positions = new Float32Array(rayDivisions * 3);
|
|
15
|
+
const vec3 = new Vector3();
|
|
16
|
+
const v2_1 = new Vector2();
|
|
17
|
+
const v2_2 = new Vector2();
|
|
18
|
+
$:
|
|
19
|
+
intersection = teleportIntersection[handedness];
|
|
20
|
+
const setCurvePoints = (alpha = 0.3) => {
|
|
21
|
+
if (intersection.current === void 0)
|
|
22
|
+
return;
|
|
23
|
+
const rayEnd = intersection.current.point;
|
|
24
|
+
targetRay.getWorldPosition(rayStart);
|
|
25
|
+
rayMidpoint.x = (rayStart.x + rayEnd.x) / 2;
|
|
26
|
+
rayMidpoint.y = (rayStart.y + rayEnd.y) / 2;
|
|
27
|
+
rayMidpoint.z = (rayStart.z + rayEnd.z) / 2;
|
|
28
|
+
const arc = Math.log1p(
|
|
29
|
+
v2_1.set(rayStart.x, rayStart.z).distanceTo(v2_2.set(rayEnd.x, rayEnd.z))
|
|
30
|
+
);
|
|
31
|
+
rayMidpoint.y += arc;
|
|
32
|
+
curve.v0.lerp(rayStart, alpha);
|
|
33
|
+
curve.v1.lerp(rayMidpoint, alpha);
|
|
34
|
+
curve.v2.lerp(rayEnd, alpha);
|
|
35
|
+
for (let i = 0, j = 0; i < rayDivisions; i += 1, j += 3) {
|
|
36
|
+
const t = i / rayDivisions;
|
|
37
|
+
curve.getPoint(t, vec3);
|
|
38
|
+
positions[j + 0] = vec3.x;
|
|
39
|
+
positions[j + 1] = vec3.y;
|
|
40
|
+
positions[j + 2] = vec3.z;
|
|
41
|
+
}
|
|
42
|
+
lineGeometry.setPositions(positions);
|
|
43
|
+
};
|
|
44
|
+
const { start, stop } = useFrame(
|
|
45
|
+
() => {
|
|
46
|
+
setCurvePoints();
|
|
47
|
+
},
|
|
48
|
+
{ autostart: false }
|
|
49
|
+
);
|
|
50
|
+
$:
|
|
51
|
+
if ($intersection === void 0) {
|
|
52
|
+
stop();
|
|
53
|
+
} else {
|
|
54
|
+
setCurvePoints(1);
|
|
55
|
+
start();
|
|
56
|
+
}
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<slot>
|
|
60
|
+
<T
|
|
61
|
+
is={Line2}
|
|
62
|
+
visible={$intersection !== undefined}
|
|
63
|
+
position.z={-0.01}
|
|
64
|
+
>
|
|
65
|
+
<T is={lineGeometry} />
|
|
66
|
+
<T
|
|
67
|
+
is={LineMaterial}
|
|
68
|
+
linewidth={0.004}
|
|
69
|
+
/>
|
|
70
|
+
</T>
|
|
71
|
+
</slot>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SvelteComponent } from "svelte";
|
|
2
|
+
import { type XRTargetRaySpace } from 'three';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
handedness: 'left' | 'right';
|
|
6
|
+
targetRay: XRTargetRaySpace;
|
|
7
|
+
};
|
|
8
|
+
events: {
|
|
9
|
+
[evt: string]: CustomEvent<any>;
|
|
10
|
+
};
|
|
11
|
+
slots: {
|
|
12
|
+
default: {};
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export type TeleportRayProps = typeof __propDef.props;
|
|
16
|
+
export type TeleportRayEvents = typeof __propDef.events;
|
|
17
|
+
export type TeleportRaySlots = typeof __propDef.slots;
|
|
18
|
+
export default class TeleportRay extends SvelteComponent<TeleportRayProps, TeleportRayEvents, TeleportRaySlots> {
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -8,7 +8,3 @@ export declare const gaze: CurrentWritable<XRController | undefined>;
|
|
|
8
8
|
* Provides a reference to a current XRController, filtered by handedness.
|
|
9
9
|
*/
|
|
10
10
|
export declare const useController: (handedness: XRHandedness) => CurrentWritable<XRController | undefined>;
|
|
11
|
-
/**
|
|
12
|
-
* Provides a reference to the gamepad attached to a current XRController.
|
|
13
|
-
*/
|
|
14
|
-
export declare const useGamepad: (handedness: 'left' | 'right') => CurrentWritable<Gamepad | undefined>;
|
|
@@ -2,10 +2,6 @@ import { currentWritable } from '@threlte/core';
|
|
|
2
2
|
export const left = currentWritable(undefined);
|
|
3
3
|
export const right = currentWritable(undefined);
|
|
4
4
|
export const gaze = currentWritable(undefined);
|
|
5
|
-
const gamepadLeft = currentWritable(undefined);
|
|
6
|
-
const gamepadRight = currentWritable(undefined);
|
|
7
|
-
left.subscribe((value) => gamepadLeft.set(value?.inputSource.gamepad));
|
|
8
|
-
right.subscribe((value) => gamepadRight.set(value?.inputSource.gamepad));
|
|
9
5
|
/**
|
|
10
6
|
* Provides a reference to a current XRController, filtered by handedness.
|
|
11
7
|
*/
|
|
@@ -17,16 +13,7 @@ export const useController = (handedness) => {
|
|
|
17
13
|
return right;
|
|
18
14
|
case 'none':
|
|
19
15
|
return gaze;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Provides a reference to the gamepad attached to a current XRController.
|
|
24
|
-
*/
|
|
25
|
-
export const useGamepad = (handedness) => {
|
|
26
|
-
switch (handedness) {
|
|
27
|
-
case 'left':
|
|
28
|
-
return gamepadLeft;
|
|
29
|
-
case 'right':
|
|
30
|
-
return gamepadRight;
|
|
16
|
+
default:
|
|
17
|
+
throw new Error('useController handedness must be left, right, or none.');
|
|
31
18
|
}
|
|
32
19
|
};
|
package/dist/hooks/useHand.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type { XRJointSpace } from 'three';
|
|
2
2
|
import type { HandJoints } from '../lib/handJoints';
|
|
3
3
|
/**
|
|
4
4
|
* Provides a reference to a requested hand joint, once available.
|
|
5
5
|
*/
|
|
6
|
-
export declare const useHandJoint: (handedness: 'left' | 'right', joint: HandJoints) => import("@threlte/core").CurrentWritable<
|
|
6
|
+
export declare const useHandJoint: (handedness: 'left' | 'right', joint: HandJoints) => import("@threlte/core").CurrentWritable<XRJointSpace | undefined>;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import type { Group } from 'three';
|
|
2
|
+
export declare const useHeadset: () => Readonly<Group>;
|
package/dist/hooks/useHeadset.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="webxr" />
|
|
2
|
-
import
|
|
3
|
-
export type HitTestCallback = (hitMatrix:
|
|
2
|
+
import { Matrix4 } from 'three';
|
|
3
|
+
export type HitTestCallback = (hitMatrix: Matrix4, hit: XRHitTestResult | undefined) => void;
|
|
4
4
|
export type UseHitTestOptions = {
|
|
5
5
|
/**
|
|
6
6
|
* The ray source when performing hit testing.
|
package/dist/hooks/useHitTest.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Matrix4 } from 'three';
|
|
2
2
|
import { useThrelte, useFrame, watch, currentWritable } from '@threlte/core';
|
|
3
3
|
import { useXR } from './useXR';
|
|
4
4
|
import { useController } from './useController';
|
|
@@ -17,12 +17,14 @@ export const useHitTest = (hitTestCallback, options = {}) => {
|
|
|
17
17
|
const source = options.source ?? 'viewer';
|
|
18
18
|
const { xr } = useThrelte().renderer;
|
|
19
19
|
const xrState = useXR();
|
|
20
|
-
const hitMatrix = new
|
|
20
|
+
const hitMatrix = new Matrix4();
|
|
21
21
|
let hitTestSource = currentWritable(undefined);
|
|
22
22
|
if (source === 'viewer') {
|
|
23
23
|
watch(xrState.session, async (session) => {
|
|
24
|
-
if (session === undefined)
|
|
24
|
+
if (session === undefined) {
|
|
25
|
+
hitTestSource.set(undefined);
|
|
25
26
|
return;
|
|
27
|
+
}
|
|
26
28
|
const space = await session.requestReferenceSpace('viewer');
|
|
27
29
|
hitTestSource.set(await session.requestHitTestSource?.({ space }));
|
|
28
30
|
});
|
|
@@ -31,14 +33,18 @@ export const useHitTest = (hitTestCallback, options = {}) => {
|
|
|
31
33
|
const controller = useController(source === 'leftInput' ? 'left' : 'right');
|
|
32
34
|
const hand = useController(source === 'leftInput' ? 'left' : 'right');
|
|
33
35
|
watch([xrState.session, controller], async ([session, input]) => {
|
|
34
|
-
if (input === undefined || session === undefined)
|
|
36
|
+
if (input === undefined || session === undefined) {
|
|
37
|
+
hitTestSource.set(undefined);
|
|
35
38
|
return;
|
|
39
|
+
}
|
|
36
40
|
const space = input.inputSource.targetRaySpace;
|
|
37
41
|
hitTestSource.set(await session.requestHitTestSource?.({ space }));
|
|
38
42
|
});
|
|
39
43
|
watch([xrState.session, hand], async ([session, input]) => {
|
|
40
|
-
if (input === undefined || session === undefined)
|
|
44
|
+
if (input === undefined || session === undefined) {
|
|
45
|
+
hitTestSource.set(undefined);
|
|
41
46
|
return;
|
|
47
|
+
}
|
|
42
48
|
const space = input.inputSource.targetRaySpace;
|
|
43
49
|
hitTestSource.set(await session.requestHitTestSource?.({ space }));
|
|
44
50
|
});
|
|
@@ -56,7 +62,11 @@ export const useHitTest = (hitTestCallback, options = {}) => {
|
|
|
56
62
|
hitMatrix.fromArray(pose.transform.matrix);
|
|
57
63
|
hitTestCallback(hitMatrix, hit);
|
|
58
64
|
}, { autostart: false });
|
|
59
|
-
watch(hitTestSource, (testSource) => {
|
|
65
|
+
watch([xrState.isPresenting, hitTestSource], ([isPresenting, testSource]) => {
|
|
66
|
+
if (!isPresenting) {
|
|
67
|
+
stop();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
60
70
|
if (testSource === undefined) {
|
|
61
71
|
stop();
|
|
62
72
|
// Execute callback one last time to inform consumers of no hits.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Quaternion, type Vector3, type Vector3Tuple } from 'three';
|
|
2
2
|
/**
|
|
3
3
|
* Returns a callback to teleport the player from the world origin to a position and optional orientation.
|
|
4
4
|
*
|
|
@@ -14,4 +14,4 @@ import * as THREE from 'three';
|
|
|
14
14
|
*
|
|
15
15
|
* teleport(vec3, quat)
|
|
16
16
|
*/
|
|
17
|
-
export declare const useTeleport: () => (position:
|
|
17
|
+
export declare const useTeleport: () => (position: Vector3 | Vector3Tuple, orientation?: Quaternion) => void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Quaternion } from 'three';
|
|
2
2
|
import { useThrelte } from '@threlte/core';
|
|
3
|
-
const quaternion = new
|
|
3
|
+
const quaternion = new Quaternion();
|
|
4
4
|
const offset = { x: 0, y: 0, z: 0 };
|
|
5
5
|
/**
|
|
6
6
|
* Returns a callback to teleport the player from the world origin to a position and optional orientation.
|
package/dist/index.d.ts
CHANGED
|
@@ -4,10 +4,17 @@ export { default as XRButton } from './components/XRButton.svelte';
|
|
|
4
4
|
export { default as Controller } from './components/Controller.svelte';
|
|
5
5
|
export { default as Hand } from './components/Hand.svelte';
|
|
6
6
|
export { default as Headset } from './components/Headset.svelte';
|
|
7
|
-
export { default as TeleportControls } from './components/TeleportControls.svelte';
|
|
8
7
|
export { default as XR } from './components/XR.svelte';
|
|
9
8
|
export { getXRSupportState } from './lib/getXRSupportState';
|
|
10
9
|
export { toggleXRSession } from './lib/toggleXRSession';
|
|
11
10
|
export { handJoints } from './lib/handJoints';
|
|
12
|
-
export
|
|
13
|
-
export
|
|
11
|
+
export { pointerControls } from './plugins/pointerControls';
|
|
12
|
+
export { teleportControls } from './plugins/teleportControls';
|
|
13
|
+
export { useController } from './hooks/useController';
|
|
14
|
+
export { useHand } from './hooks/useHand';
|
|
15
|
+
export { useHandJoint } from './hooks/useHandJoint';
|
|
16
|
+
export { useHeadset } from './hooks/useHeadset';
|
|
17
|
+
export { useHitTest } from './hooks/useHitTest';
|
|
18
|
+
export { useTeleport } from './hooks/useTeleport';
|
|
19
|
+
export { useXR } from './hooks/useXR';
|
|
20
|
+
export type { XRSessionEventType, XRControllerEventType, XRHandEventType, XRSessionEvent, XRControllerEvent, XRController, XRHand, XRHandEvent, } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,23 @@
|
|
|
1
|
+
// Components
|
|
1
2
|
export { default as ARButton } from './components/ARButton.svelte';
|
|
2
3
|
export { default as VRButton } from './components/VRButton.svelte';
|
|
3
4
|
export { default as XRButton } from './components/XRButton.svelte';
|
|
4
5
|
export { default as Controller } from './components/Controller.svelte';
|
|
5
6
|
export { default as Hand } from './components/Hand.svelte';
|
|
6
7
|
export { default as Headset } from './components/Headset.svelte';
|
|
7
|
-
export { default as TeleportControls } from './components/TeleportControls.svelte';
|
|
8
8
|
export { default as XR } from './components/XR.svelte';
|
|
9
|
+
// Utilities
|
|
9
10
|
export { getXRSupportState } from './lib/getXRSupportState';
|
|
10
11
|
export { toggleXRSession } from './lib/toggleXRSession';
|
|
11
12
|
export { handJoints } from './lib/handJoints';
|
|
12
|
-
|
|
13
|
+
// Plugins
|
|
14
|
+
export { pointerControls } from './plugins/pointerControls';
|
|
15
|
+
export { teleportControls } from './plugins/teleportControls';
|
|
16
|
+
// Hooks
|
|
17
|
+
export { useController } from './hooks/useController';
|
|
18
|
+
export { useHand } from './hooks/useHand';
|
|
19
|
+
export { useHandJoint } from './hooks/useHandJoint';
|
|
20
|
+
export { useHeadset } from './hooks/useHeadset';
|
|
21
|
+
export { useHitTest } from './hooks/useHitTest';
|
|
22
|
+
export { useTeleport } from './hooks/useTeleport';
|
|
23
|
+
export { useXR } from './hooks/useXR';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const setupControllers: () => void;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { XRControllerModelFactory } from 'three/examples/jsm/webxr/XRControllerModelFactory';
|
|
2
|
+
import { useThrelte } from '@threlte/core';
|
|
3
|
+
import { onMount } from 'svelte';
|
|
4
|
+
import { useHandTrackingState } from './useHandTrackingState';
|
|
5
|
+
import { gaze, left, right } from '../hooks/useController';
|
|
6
|
+
import { controllerDispatchers } from './stores';
|
|
7
|
+
export const setupControllers = () => {
|
|
8
|
+
const factory = new XRControllerModelFactory();
|
|
9
|
+
const stores = { left, right, none: gaze };
|
|
10
|
+
const { xr } = useThrelte().renderer;
|
|
11
|
+
const hasHands = useHandTrackingState();
|
|
12
|
+
const controllers = [xr.getController(0), xr.getController(1)];
|
|
13
|
+
const indexMap = new Map();
|
|
14
|
+
controllers.forEach((targetRay, index) => {
|
|
15
|
+
indexMap.set(targetRay, {
|
|
16
|
+
targetRay,
|
|
17
|
+
grip: xr.getControllerGrip(index),
|
|
18
|
+
model: factory.createControllerModel(targetRay)
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
onMount(() => {
|
|
22
|
+
const dispatch = (event) => {
|
|
23
|
+
if (hasHands())
|
|
24
|
+
return;
|
|
25
|
+
const { data } = event;
|
|
26
|
+
controllerDispatchers[data.handedness]?.current?.(event.type, event);
|
|
27
|
+
};
|
|
28
|
+
function handleConnected(event) {
|
|
29
|
+
const { model, targetRay, grip } = indexMap.get(this);
|
|
30
|
+
const { data: inputSource } = event;
|
|
31
|
+
stores[event.data.handedness].set({
|
|
32
|
+
inputSource,
|
|
33
|
+
targetRay,
|
|
34
|
+
grip,
|
|
35
|
+
model
|
|
36
|
+
});
|
|
37
|
+
dispatch(event);
|
|
38
|
+
}
|
|
39
|
+
const handleDisconnected = (event) => {
|
|
40
|
+
dispatch(event);
|
|
41
|
+
stores[event.data.handedness].set(undefined);
|
|
42
|
+
};
|
|
43
|
+
for (const targetRay of controllers) {
|
|
44
|
+
targetRay.addEventListener('connected', handleConnected);
|
|
45
|
+
targetRay.addEventListener('disconnected', handleDisconnected);
|
|
46
|
+
targetRay.addEventListener('select', dispatch);
|
|
47
|
+
targetRay.addEventListener('selectstart', dispatch);
|
|
48
|
+
targetRay.addEventListener('selectend', dispatch);
|
|
49
|
+
targetRay.addEventListener('squeeze', dispatch);
|
|
50
|
+
targetRay.addEventListener('squeezestart', dispatch);
|
|
51
|
+
targetRay.addEventListener('squeezeend', dispatch);
|
|
52
|
+
}
|
|
53
|
+
return () => {
|
|
54
|
+
for (const targetRay of controllers) {
|
|
55
|
+
targetRay.removeEventListener('connected', handleConnected);
|
|
56
|
+
targetRay.removeEventListener('disconnected', handleDisconnected);
|
|
57
|
+
targetRay.removeEventListener('select', dispatch);
|
|
58
|
+
targetRay.removeEventListener('selectstart', dispatch);
|
|
59
|
+
targetRay.removeEventListener('selectend', dispatch);
|
|
60
|
+
targetRay.removeEventListener('squeeze', dispatch);
|
|
61
|
+
targetRay.removeEventListener('squeezestart', dispatch);
|
|
62
|
+
targetRay.removeEventListener('squeezeend', dispatch);
|
|
63
|
+
}
|
|
64
|
+
stores.left.set(undefined);
|
|
65
|
+
stores.right.set(undefined);
|
|
66
|
+
stores.none.set(undefined);
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const setupHands: () => void;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { XRHandModelFactory } from 'three/examples/jsm/webxr/XRHandModelFactory';
|
|
2
|
+
import { useThrelte } from '@threlte/core';
|
|
3
|
+
import { onMount } from 'svelte';
|
|
4
|
+
import { left, right } from '../hooks/useHand';
|
|
5
|
+
import { useHandTrackingState } from './useHandTrackingState';
|
|
6
|
+
import { handDispatchers } from './stores';
|
|
7
|
+
export const setupHands = () => {
|
|
8
|
+
const factory = new XRHandModelFactory();
|
|
9
|
+
const stores = { left, right };
|
|
10
|
+
const { xr } = useThrelte().renderer;
|
|
11
|
+
const hasHands = useHandTrackingState();
|
|
12
|
+
const handSpaces = [xr.getHand(0), xr.getHand(1)];
|
|
13
|
+
const map = new Map();
|
|
14
|
+
handSpaces.forEach((handSpace, index) => {
|
|
15
|
+
map.set(handSpace, {
|
|
16
|
+
hand: handSpace,
|
|
17
|
+
targetRay: xr.getController(index),
|
|
18
|
+
model: factory.createHandModel(handSpace, 'mesh')
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
onMount(() => {
|
|
22
|
+
const dispatch = (event) => {
|
|
23
|
+
if (!hasHands())
|
|
24
|
+
return;
|
|
25
|
+
const handEvent = event;
|
|
26
|
+
const handedness = ('handedness' in handEvent) ? handEvent.handedness : handEvent.data.handedness;
|
|
27
|
+
handDispatchers[handedness]?.current?.(event.type, event);
|
|
28
|
+
};
|
|
29
|
+
function handleConnected(event) {
|
|
30
|
+
const hand = this;
|
|
31
|
+
const { model, targetRay } = map.get(this);
|
|
32
|
+
const { data } = event;
|
|
33
|
+
const { handedness, hand: inputSource } = data;
|
|
34
|
+
stores[handedness].set({
|
|
35
|
+
hand,
|
|
36
|
+
model,
|
|
37
|
+
inputSource,
|
|
38
|
+
targetRay
|
|
39
|
+
});
|
|
40
|
+
dispatch(event);
|
|
41
|
+
}
|
|
42
|
+
const handleDisconnected = (event) => {
|
|
43
|
+
dispatch(event);
|
|
44
|
+
stores[event.data.handedness].set(undefined);
|
|
45
|
+
};
|
|
46
|
+
for (const handSpace of handSpaces) {
|
|
47
|
+
handSpace.addEventListener('connected', handleConnected);
|
|
48
|
+
handSpace.addEventListener('disconnected', handleDisconnected);
|
|
49
|
+
handSpace.addEventListener('pinchstart', dispatch);
|
|
50
|
+
handSpace.addEventListener('pinchend', dispatch);
|
|
51
|
+
}
|
|
52
|
+
return () => {
|
|
53
|
+
for (const handSpace of handSpaces) {
|
|
54
|
+
handSpace.removeEventListener('connected', handleConnected);
|
|
55
|
+
handSpace.removeEventListener('disconnected', handleDisconnected);
|
|
56
|
+
handSpace.removeEventListener('pinchstart', dispatch);
|
|
57
|
+
handSpace.removeEventListener('pinchend', dispatch);
|
|
58
|
+
}
|
|
59
|
+
stores.left.set(undefined);
|
|
60
|
+
stores.right.set(undefined);
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { Group } from 'three';
|
|
2
2
|
import { useThrelte, useFrame, watch } from '@threlte/core';
|
|
3
|
-
import { useXR } from '../hooks';
|
|
3
|
+
import { useXR } from '../hooks/useXR';
|
|
4
4
|
export const headset = new Group();
|
|
5
|
-
export const
|
|
5
|
+
export const setupHeadset = () => {
|
|
6
6
|
const { renderer, camera } = useThrelte();
|
|
7
|
-
const xrState = useXR();
|
|
8
7
|
const { xr } = renderer;
|
|
9
8
|
const immersiveFrame = useFrame(() => {
|
|
10
9
|
const space = xr.getReferenceSpace();
|
|
@@ -23,7 +22,7 @@ export const useUpdateHeadset = () => {
|
|
|
23
22
|
headset.position.copy(camera.current.position);
|
|
24
23
|
headset.quaternion.copy(camera.current.quaternion);
|
|
25
24
|
}, { autostart: false, invalidate: false });
|
|
26
|
-
watch(
|
|
25
|
+
watch(useXR().isPresenting, (isPresenting) => {
|
|
27
26
|
if (isPresenting) {
|
|
28
27
|
immersiveFrame.start();
|
|
29
28
|
nonImmersiveFrame.stop();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const setupRaf: () => void;
|
|
@@ -3,7 +3,7 @@ import { set_raf } from 'svelte/internal';
|
|
|
3
3
|
import { onDestroy } from 'svelte';
|
|
4
4
|
import { watch } from '@threlte/core';
|
|
5
5
|
import { session } from './stores';
|
|
6
|
-
export const
|
|
6
|
+
export const setupRaf = () => {
|
|
7
7
|
if (typeof window === 'undefined')
|
|
8
8
|
return;
|
|
9
9
|
const browserRaf = (fn) => requestAnimationFrame(fn);
|
|
@@ -11,7 +11,7 @@ export const updateRaf = () => {
|
|
|
11
11
|
set_raf((fn) => currentRaf.fn(fn));
|
|
12
12
|
watch(session, (session) => {
|
|
13
13
|
if (session) {
|
|
14
|
-
currentRaf.fn = (fn) =>
|
|
14
|
+
currentRaf.fn = (fn) => session.requestAnimationFrame(fn);
|
|
15
15
|
}
|
|
16
16
|
else {
|
|
17
17
|
currentRaf.fn = browserRaf;
|