[Meta OpenXR] Fix Quest 3 Hand Tracking Disconnect When Using Controllers
Solution
Unity 2022.3.x - Unity 6.3.x
Published 18 days ago
XR Hand tracking ceases immediately when a Quest 3 Controller is active or held. This occurs despite having XR Hands and Meta OpenXR features installed, preventing hybrid input scenarios where both controllers and hands are required simultaneously.
Ensure the XRLoader remains active at startup and enable the Simultaneous Hands and Controllers feature within the Meta OpenXR settings.
The root cause is typically associated with the lifecycle management of XRSubsystem instances or the default exclusive input mode of the Meta OpenXR provider. If your script manually interferes with the XRLoader, hand tracking providers often fail to restart correctly when controllers are present.
To ensure consistent behavior, the XRLoader must remain operational from the application launch. Furthermore, the Meta Quest runtime requires an explicit feature flag to be enabled for concurrent input.
- Open Project Settings > XR Plug-in Management > OpenXR.
- In the Features tab (Android icon), locate the Meta Quest Feature list.
- Enable the Hand Tracking feature and the Meta Quest Support feature group.
- Locate the Simultaneous Hands and Controllers checkbox and ensure it is enabled to allow both input types.
- Verify that your script does not call
StopSubsystems()on the XRLoader during the initialAwakeorStartphase.
Additional Tips:
- Check that the
AndroidManifest.xmlincludes thecom.oculus.permission.HAND_TRACKINGpermission to prevent system-level blocking. - Ensure the
XRHandSubsystemis being correctly retrieved from the XRLoader if you are performing manual lifecycle checks. - For Unity 6, verify that the Meta XR SDK version is 65.0 or higher to support the latest SHAC (Simultaneous Hands and Controllers) features.
using UnityEngine;
using UnityEngine.XR.Management;
using UnityEngine.XR.Hands;
public class XRInputLifecycleManager : MonoBehaviour
{
private void Start()
{
// Ensure the loader is running and manually start the hand subsystem if it failed to initialize
if (XRGeneralSettings.Instance.Manager.activeLoader != null)
{
var handSubsystem = XRGeneralSettings.Instance.Manager.activeLoader.GetLoadedSubsystem<XRHandSubsystem>();
if (handSubsystem != null && !handSubsystem.running)
{
handSubsystem.Start();
}
}
}
}
Related Posts Haven't quite found a solution to your problem? We think these posts might help you.
Content inspired by a Unity discussion post.