UOculusXRHandComponent for poke detection| Component | What it demonstrates | Key concepts |
|---|---|---|
AFingerTipPokeTool | Near-field poke interaction using bone capsules | UOculusXRHandComponent->CollisionCapsules binding |
ARayTool | Far-field ray interaction with cone fallback | GetPointerPose(), 20° cone fallback, 1.2x focus hysteresis |
PinchStateModule | Pinch detection state machine | None→PinchDown→PinchStay→PinchUp transitions |
AControllerBox | HMD-following controller container | Max distance threshold, position tracking |
ACollidableInteractable | Interactable state machine | Default→Proximity→Contact→Action states |
Toy train scene | Interactive environment | Locomotive, crossing gate, windmill |
AFingerTipPokeTool binds bone capsules from UOculusXRHandComponent->CollisionCapsules to detect contact. Far-field ray interactions use ARayTool with GetPointerPose() for aiming; when the ray cannot find a target, a 20° cone fallback expands the search area. Focus hysteresis (1.2x multiplier) prevents rapid switching between nearby targets. The PinchStateModule tracks pinch through four states: None, PinchDown, PinchStay, and PinchUp. AControllerBox follows the HMD position with a maximum distance threshold. ACollidableInteractable transitions through Default, Proximity, Contact, and Action states.AFingerTipPokeTool creates collision capsules bound to finger bones from the OculusXR hand component:// AFingerTipPokeTool binds collision capsules from the hand component // CollisionCapsules array maps to fingertip bones `UOculusXRHandComponent`* HandComp = GetHandComponent(); TArray<FCapsuleInfo>& Capsules = HandComp->CollisionCapsules; // Each capsule follows its bone transform for frame-accurate poke detection
ARayTool implements ray-based selection with a cone fallback and focus hysteresis:// Primary ray from GetPointerPose() // If no hit within ray, expand to 20° cone for easier acquisition // Focus hysteresis: selected target stays active within 1.2x the selection distance // This prevents rapid focus switching between adjacent targets float FocusHysteresis = 1.2f;
// Pinch states: None → PinchDown → PinchStay → PinchUp → None
// PinchDown: pinch strength exceeds activation threshold
// PinchStay: pinch held above release threshold
// PinchUp: pinch strength drops below release threshold
enum class EPinchState { None, PinchDown, PinchStay, PinchUp };
// Three custom collision channels: // 1. FarField - used by ARayTool for ray and cone traces // 2. HandCapsuleOrTool - used by AFingerTipPokeTool for poke detection // 3. InteractableCollisionZone - defines interactable trigger volumes // Priority routing: near-field (poke) takes precedence over far-field (ray)
ACollidableInteractable manages interaction through four states:// State transitions:
// Default: no hand interaction detected
// Proximity: hand enters InteractableCollisionZone
// Contact: fingertip capsule touches interactable surface
// Action: pinch or poke completes the interaction
enum class EInteractableState { Default, Proximity, Contact, Action };
ACollidableInteractable.