Skip to content

Commit 7c1e39c

Browse files
author
Kailean O'Keefe
committed
chore: Saving progress
1 parent e77ec5e commit 7c1e39c

File tree

7 files changed

+162
-33
lines changed

7 files changed

+162
-33
lines changed

‎examples/hit-testing/package.json‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
{
22
"name": "hit-testing",
33
"dependencies": {
4-
"@react-three/xr": "workspace:~"
4+
"@react-three/uikit": "^0.8.21",
5+
"@react-three/xr": "workspace:~",
6+
"@react-three/handle": "workspace:~"
57
},
68
"scripts": {
79
"dev": "vite --host",
810
"build": "vite build",
911
"check:eslint": "eslint \"src/**/*.{ts,tsx}\"",
1012
"fix:eslint": "eslint \"src/**/*.{ts,tsx}\" --fix"
1113
}
12-
}
14+
}

‎examples/hit-testing/src/app.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import { Duck } from './duck.js'
99
import { Ducks } from './ducks.js'
1010
import { HitTest } from './hit-test.js'
1111

12-
export let hitTestMatrices: Partial<Record<XRHandedness, Matrix4 | undefined>> = {}
12+
export let hitTestMatrices: Partial<Record<XRHandedness | 'duck', Matrix4 | undefined>> = {}
1313

1414
export function onResults(
15-
handedness: XRHandedness,
15+
handedness: XRHandedness | 'duck',
1616
results: Array<XRHitTestResult>,
1717
getWorldMatrix: (target: Matrix4, hit: XRHitTestResult) => void,
1818
) {
Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,64 @@
11
import { useFrame } from '@react-three/fiber'
2+
import { Root, Text } from '@react-three/uikit'
23
import {
34
DefaultXRController,
45
XRHitTest,
56
XRSpace,
67
useXRInputSourceState,
78
useXRInputSourceStateContext,
89
} from '@react-three/xr'
9-
import { useState } from 'react'
10+
import { useRef, useState } from 'react'
1011
import { onResults } from './app.js'
12+
import { useTestDistanceToFloor } from './useTestDistanceToFloor.js'
1113

14+
const defaultControllerMessage = 'Press the A button to test distance to floor'
1215
export const CustomController = () => {
13-
const [allowRightHandHitTesting, setAllowRightHandHitTesting] = useState(false)
16+
const [controllerText, setControllerText] = useState<string>(defaultControllerMessage)
17+
const isPressed = useRef<boolean>(false)
18+
const timeoutRef = useRef<NodeJS.Timeout | null>(null)
19+
const testDistance = useTestDistanceToFloor()
20+
1421
const state = useXRInputSourceStateContext()
1522
const rightController = useXRInputSourceState('controller', 'right')
16-
const isLeftHanded = state.inputSource.handedness === 'left'
23+
const isRightHand = state.inputSource.handedness === 'right'
1724

1825
useFrame(() => {
19-
if (rightController?.gamepad?.['a-button']?.state === 'pressed') {
20-
setAllowRightHandHitTesting((prev) => !prev)
26+
if (rightController?.gamepad?.['a-button']?.state === 'pressed' && !isPressed.current) {
27+
testDistance().then((result) => {
28+
if (result !== undefined) {
29+
setControllerText(`Distance to Floor: ${result.toFixed(2)} meters`)
30+
} else {
31+
setControllerText('Unable to calculate distance. Try looking towards the floor.')
32+
}
33+
34+
if (timeoutRef.current) {
35+
clearTimeout(timeoutRef.current)
36+
}
37+
timeoutRef.current = setTimeout(() => {
38+
setControllerText(defaultControllerMessage)
39+
}, 5000)
40+
})
41+
isPressed.current = true
42+
}
43+
44+
if (rightController?.gamepad?.['a-button']?.state === 'default') {
45+
isPressed.current = false
2146
}
2247
})
2348

2449
return (
2550
<>
2651
<DefaultXRController />
27-
{(isLeftHanded || allowRightHandHitTesting) && (
28-
<XRSpace space={state.inputSource.targetRaySpace}>
29-
<XRHitTest onResults={onResults.bind(null, state.inputSource.handedness)} />
30-
</XRSpace>
52+
{isRightHand && (
53+
<Root transformTranslateY={-2.9} transformRotateX={-25}>
54+
<Text fontSize={2} color={'white'}>
55+
{controllerText}
56+
</Text>
57+
</Root>
3158
)}
59+
<XRSpace space={state.inputSource.targetRaySpace}>
60+
<XRHitTest onResults={onResults.bind(null, state.inputSource.handedness)} />
61+
</XRSpace>
3262
</>
3363
)
3464
}

‎examples/hit-testing/src/duck.tsx‎

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
* license: CC0
88
*/
99
import { useGLTF } from '@react-three/drei'
10+
import { useFrame } from '@react-three/fiber'
11+
import { Handle, HandleStore } from '@react-three/handle'
12+
import { useXRHitTestSource } from '@react-three/xr'
13+
import { useRef, useState } from 'react'
14+
import { Group } from 'three'
15+
import { onResults } from './app.js'
16+
import { Reticle } from './reticle.js'
1017

1118
// const MODEL = 'https://vazxmixjsiawhamofees.supabase.co/storage/v1/object/public/models/duck/model.gltf'
1219
const MODEL = 'duck.gltf'
@@ -15,31 +22,65 @@ useGLTF.preload(MODEL)
1522

1623
export const Duck = (props: any) => {
1724
const { nodes, materials } = useGLTF(MODEL) as any
25+
const [isBeingGrabbed, setisBeingGrabbed] = useState(false)
26+
const hitTestRefPoint = useRef<Group>(null)
27+
const duckGroup = useRef<Group>(null)
28+
const hitTestSource = useXRHitTestSource(hitTestRefPoint, 'plane')
29+
const handleRef = useRef<HandleStore<unknown>>(null)
30+
31+
useFrame((_, __, frame: XRFrame | undefined) => {
32+
if (frame && hitTestSource && isBeingGrabbed) {
33+
const hitTestResults = frame.getHitTestResults(hitTestSource.source)
34+
onResults('duck', hitTestResults, hitTestSource.getWorldMatrix)
35+
}
36+
})
1837

1938
return (
20-
<group {...props} dispose={null}>
21-
<mesh
22-
geometry={nodes.character_duck.geometry}
23-
material={nodes.character_duck.material}
24-
rotation={[Math.PI / 2, 0, 0]}
39+
<group ref={duckGroup} {...props} dispose={null}>
40+
<Handle
41+
ref={handleRef}
42+
handleRef={duckGroup}
43+
apply={(state) => {
44+
if (state.last) {
45+
setisBeingGrabbed(false)
46+
} else {
47+
setisBeingGrabbed(true)
48+
}
49+
50+
duckGroup.current?.position.copy(state.current.position)
51+
duckGroup.current?.quaternion.copy(state.current.quaternion)
52+
}}
2553
>
2654
<mesh
27-
geometry={nodes.character_duckArmLeft.geometry}
28-
material={nodes.character_duckArmLeft.material}
29-
position={[0.2, 0, -0.63]}
30-
/>
31-
<mesh
32-
geometry={nodes.character_duckArmRight.geometry}
33-
material={nodes.character_duckArmRight.material}
34-
position={[-0.2, 0, -0.63]}
35-
/>
55+
geometry={nodes.character_duck.geometry}
56+
material={nodes.character_duck.material}
57+
rotation={[Math.PI / 2, 0, 0]}
58+
>
59+
<mesh
60+
geometry={nodes.character_duckArmLeft.geometry}
61+
material={nodes.character_duckArmLeft.material}
62+
position={[0.2, 0, -0.63]}
63+
/>
64+
<mesh
65+
geometry={nodes.character_duckArmRight.geometry}
66+
material={nodes.character_duckArmRight.material}
67+
position={[-0.2, 0, -0.63]}
68+
/>
3669

37-
<group position={[0, 0, -0.7]}>
38-
<mesh geometry={nodes.Cube1338.geometry} material={nodes.Cube1338.material} />
39-
<mesh geometry={nodes.Cube1338_1.geometry} material={materials['Yellow.043']} />
40-
<mesh geometry={nodes.Cube1338_2.geometry} material={materials['Black.027']} />
70+
<group position={[0, 0, -0.7]}>
71+
<mesh geometry={nodes.Cube1338.geometry} material={nodes.Cube1338.material} />
72+
<mesh geometry={nodes.Cube1338_1.geometry} material={materials['Yellow.043']} />
73+
<mesh geometry={nodes.Cube1338_2.geometry} material={materials['Black.027']} />
74+
</group>
75+
</mesh>
76+
<group ref={hitTestRefPoint}>
77+
<mesh position={[0, -0.5, 0]}>
78+
<cylinderGeometry args={[0.01, 0.01, 1, 8]} />
79+
<meshBasicMaterial color="red" />
80+
</mesh>
4181
</group>
42-
</mesh>
82+
{isBeingGrabbed && <Reticle handedness="duck" />}
83+
</Handle>
4384
</group>
4485
)
4586
}

‎examples/hit-testing/src/reticle.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const ReticleMesh = forwardRef<Mesh, ThreeElements['mesh']>((props, ref) => {
1818
)
1919
})
2020

21-
export const Reticle = memo(({ handedness }: { handedness: XRHandedness }) => {
21+
export const Reticle = memo(({ handedness }: { handedness: XRHandedness | 'duck' }) => {
2222
const ref = useRef<Mesh>(undefined)
2323

2424
useFrame(() => {

‎packages/react/xr/src/default.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ export function DefaultXRHandTouchPointer(props: DefaultXRHandTouchPointerOption
173173
* #### `model` - Options for configuring the controller apperance
174174
* #### `grabPointer` - Options for configuring the grab pointer
175175
* #### `rayPointer` - Options for configuring the ray pointer
176+
* #### `teleportPointer` - Options for configuring the teleport pointer
176177
*/
177178
export function DefaultXRController(props: DefaultXRControllerOptions) {
178179
const modelOptions = props.model

‎pnpm-lock.yaml‎

Lines changed: 55 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)