mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 03:00:14 +02:00
Pose the cockpit hands from the headset's hand tracking
- New [vr] hand_tracking (default off, Quest only for now): the Quest launcher's Settings > VR and the headset panel's VR tab, under hand steering. Two XR_EXT_hand_tracking trackers are located every XR frame: with the controllers held the Quest builds the joints from their touch sensors (XR_EXT_hand_tracking_data_source's controller source), once they are put down from its cameras. The trackers exist only while the option and hand steering are on and also serve the runtime hand mesh; the extensions (plus XR_FB_hand_tracking_aim) are asked for when either is on at launch. - Aurora skins the runtime mesh with the joints themselves (tracked pose times inverse bind pose, no curl, no grip); runtimes with joints but no mesh get a skeleton; non-finite joints put only that hand back on its grip curl. AuroraCockpitHand carries the 26 seated-frame joints and radii. - The manifest declares horizonos.permission.HAND_TRACKING (and the deprecated com.oculus.permission.HAND_TRACKING), both normal permissions with no prompt on a Quest 3, and oculus.software.handtracking as optional; without it Horizon OS keeps the app controllers-only. Bare hands then drive khr/simple_controller, so on Android a hand whose squeeze action is inactive and select active is treated as bare: with the option off it presses nothing but the menu gesture, is not drawn and feeds no Wii Remote motion. - Interaction-profile changes and tracker sources are logged. The pure rules (grasp from finger flexion, bare latch, pinch gate, bare-hand buttons, flick) live in the OpenXR-free vr/openxr_hand_tracking.h with mkw_vr_hand_tracking_tests; the driving and flick parts are wired in the next commits. Docs: OPENXR.md, docs/quest-port.md, README. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c990c595f0
commit
a21e22b605
24 files changed
+1549
-49
No files matched your search
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "vr/camera_toggle.h"
|
||||
#include "vr/openxr_driving.h"
|
||||
#include "vr/openxr_hand_tracking.h"
|
||||
#include "vr/openxr_runtime.h"
|
||||
#include "vr/openxr_settings_panel.h"
|
||||
#include "vr/openxr_wii_remote.h"
|
||||
@@ -66,6 +67,15 @@ struct OpenXRPointerScreen {
|
||||
// the game (a shoulder on the gamepad; as a Wii Remote the grips are unbound,
|
||||
// so a hand on the wheel cannot hold down a button).
|
||||
//
|
||||
// Tracked hands ([vr] hand_tracking, with hand steering): two hand trackers
|
||||
// (XR_EXT_hand_tracking) located every frame give the cockpit the hands' own
|
||||
// joints, from the controllers' touch sensors while they are held and from the
|
||||
// cameras once they are put down. On the Quest a hand that drives
|
||||
// khr/simple_controller instead of the Touch profile has bare-hand buttons
|
||||
// (openxr_hand_tracking.h): with the option off it presses nothing but the menu
|
||||
// gesture, so the manifest's hand-tracking permission changes nothing for
|
||||
// players who leave it off.
|
||||
//
|
||||
// A right-thumbstick click on its own toggles the first-person camera, as its
|
||||
// F10 checkbox does (first_person_toggle_click).
|
||||
//
|
||||
@@ -105,6 +115,13 @@ public:
|
||||
|
||||
// The cockpit state the last Sync published (also OpenXRReadDriving()).
|
||||
const DrivingSnapshot& Driving() const noexcept { return m_driving; }
|
||||
// The tracked hands' joints in the seated frame, as the last Sync located
|
||||
// them; read on the pacing thread only.
|
||||
const hand_tracking::HandJointFrame& HandJoints() const noexcept { return m_joint_frame; }
|
||||
// A hand's tracker while tracked hands keep one, else XR_NULL_HANDLE.
|
||||
XrHandTrackerEXT HandTracker(uint32_t hand) const noexcept {
|
||||
return hand < kHands ? m_hand_trackers[hand] : XR_NULL_HANDLE;
|
||||
}
|
||||
|
||||
// Publishes a remote with nothing held, at rest and not pointing, and stops
|
||||
// the haptics, for frames without focused input.
|
||||
@@ -140,6 +157,14 @@ private:
|
||||
void UpdateDriving(XrTime display_time, const driving::SeatFrame& seat,
|
||||
std::array<wii_remote::HandInputs, kHands>& hands, bool withheld);
|
||||
void ResetDriving();
|
||||
// Tracked hands: the extension's functions at Create, the trackers as the
|
||||
// settings ask for them, and both hands located for `time`, their joints
|
||||
// in `seat` when it is valid.
|
||||
void LoadHandTracking();
|
||||
void UpdateHandTrackers();
|
||||
void DestroyHandTrackers();
|
||||
void LocateHands(XrTime time, const driving::SeatFrame& seat);
|
||||
void LogInteractionProfiles();
|
||||
void UpdateRumble();
|
||||
void StopRumble();
|
||||
bool Check(XrResult result, const char* operation);
|
||||
@@ -182,6 +207,38 @@ private:
|
||||
bool m_wheel_uses_geometry = false;
|
||||
bool m_wheel_bike = false;
|
||||
DrivingSnapshot m_driving{};
|
||||
|
||||
// Tracked hands.
|
||||
struct TrackedHand {
|
||||
bool active = false; // joints located this frame
|
||||
bool seated = false; // and written into m_joint_frame, in the seated frame
|
||||
hand_tracking::Source source = hand_tracking::Source::None;
|
||||
hand_tracking::JointPositions positions{}; // application space
|
||||
// XR_FB_hand_tracking_aim: the runtime's own pinch and menu gesture.
|
||||
bool aim_valid = false;
|
||||
bool aim_pinching = false;
|
||||
bool aim_menu = false;
|
||||
bool aim_system_gesture = false;
|
||||
};
|
||||
PFN_xrCreateHandTrackerEXT m_create_hand_tracker = nullptr;
|
||||
PFN_xrDestroyHandTrackerEXT m_destroy_hand_tracker = nullptr;
|
||||
PFN_xrLocateHandJointsEXT m_locate_hand_joints = nullptr;
|
||||
bool m_hand_data_source = false; // XR_EXT_hand_tracking_data_source
|
||||
bool m_hand_aim = false; // XR_FB_hand_tracking_aim
|
||||
XrHandTrackerEXT m_hand_trackers[kHands]{};
|
||||
bool m_hand_trackers_failed = false;
|
||||
bool m_logged_hand_restart = false;
|
||||
std::array<TrackedHand, kHands> m_tracked_hands{};
|
||||
hand_tracking::HandJointFrame m_joint_frame{};
|
||||
std::array<hand_tracking::Source, kHands> m_logged_sources{hand_tracking::Source::None,
|
||||
hand_tracking::Source::None};
|
||||
// Per frame, from the actions: a controller is in the hand (its squeeze is
|
||||
// bound), and the hand drives simple_controller (Android only).
|
||||
std::array<bool, kHands> m_squeeze_active{};
|
||||
std::array<bool, kHands> m_hand_driven{};
|
||||
std::array<bool, kHands> m_pinch{};
|
||||
uint64_t m_profile_serial = 0;
|
||||
|
||||
bool m_created = false;
|
||||
bool m_logged_sync_failure = false;
|
||||
bool m_logged_pointer = false;
|
||||
|
||||
Reference in new issue
Block a user