protected bool UpdateHandData(OVRHand ovrHand, OVRSkeleton ovrSkeleton) { bool isTracked = ovrHand.IsTracked; if (ovrHand.HandConfidence == OVRHand.TrackingConfidence.High) { _lastHighConfidenceTime = Time.unscaledTime; } if (ovrHand.HandConfidence == OVRHand.TrackingConfidence.Low) { if (settingsProfile.MinimumHandConfidence == OVRHand.TrackingConfidence.High) { isTracked = false; } else { float lowConfidenceTime = Time.time - _lastHighConfidenceTime; if (settingsProfile.LowConfidenceTimeThreshold > 0 && settingsProfile.LowConfidenceTimeThreshold < lowConfidenceTime) { isTracked = false; } } } if (ControllerHandedness == Handedness.Left) { settingsProfile.CurrentLeftHandTrackingConfidence = ovrHand.HandConfidence; } else { settingsProfile.CurrentRightHandTrackingConfidence = ovrHand.HandConfidence; } if (ovrSkeleton != null) { var bones = ovrSkeleton.Bones; foreach (var bone in bones) { UpdateBone(bone); } UpdatePalm(); } HandDefinition?.UpdateHandJoints(jointPoses); // Note: After some testing, it seems when moving your hand fast, Oculus's pinch estimation data gets frozen, which leads to stuck pinches. // To counter this, we perform a distance check between thumb and index to determine if we should force the pinch to a false state. float pinchStrength = HandPoseUtils.CalculateIndexPinch(ControllerHandedness); if (pinchStrength == 0.0f) { IsPinching = false; } else { if (IsPinching) { // If we are already pinching, we make the pinch a bit sticky IsPinching = pinchStrength > 0.5f; } else { // If not yet pinching, only consider pinching if finger confidence is high IsPinching = pinchStrength > 0.85f && ovrHand.GetFingerConfidence(OVRHand.HandFinger.Index) == OVRHand.TrackingConfidence.High; } } isIndexGrabbing = HandPoseUtils.IsIndexGrabbing(ControllerHandedness); isMiddleGrabbing = HandPoseUtils.IsMiddleGrabbing(ControllerHandedness); // Pinch was also used as grab, we want to allow hand-curl grab not just pinch. // Determine pinch and grab separately if (isTracked) { IsGrabbing = isIndexGrabbing && isMiddleGrabbing; } return(isTracked); }
/// <summary> /// Update the controller data from the provided platform state /// </summary> /// <param name="interactionSourceState">The InteractionSourceState retrieved from the platform</param> public void UpdateController(OVRHand hand, OVRSkeleton ovrSkeleton, Transform trackingOrigin) { if (!Enabled || hand == null || ovrSkeleton == null) { return; } bool isTracked = UpdateHandData(hand, ovrSkeleton); IsPositionAvailable = IsRotationAvailable = isTracked; if (isTracked) { // Leverage Oculus Platform Hand Ray - instead of simulating it in a crummy way currentPointerPose.Position = trackingOrigin.TransformPoint(hand.PointerPose.position); Vector3 pointerForward = trackingOrigin.TransformDirection(hand.PointerPose.forward); Vector3 pointerUp = trackingOrigin.TransformDirection(hand.PointerPose.up); currentPointerPose.Rotation = Quaternion.LookRotation(pointerForward, pointerUp); currentGripPose = jointPoses[TrackedHandJoint.Palm]; CoreServices.InputSystem?.RaiseSourcePoseChanged(InputSource, this, currentGripPose); UpdateVelocity(); } for (int i = 0; i < Interactions?.Length; i++) { switch (Interactions[i].InputType) { case DeviceInputType.SpatialPointer: Interactions[i].PoseData = currentPointerPose; if (Interactions[i].Changed) { CoreServices.InputSystem?.RaisePoseInputChanged(InputSource, ControllerHandedness, Interactions[i].MixedRealityInputAction, currentPointerPose); } break; case DeviceInputType.SpatialGrip: Interactions[i].PoseData = currentGripPose; if (Interactions[i].Changed) { CoreServices.InputSystem?.RaisePoseInputChanged(InputSource, ControllerHandedness, Interactions[i].MixedRealityInputAction, currentGripPose); } break; case DeviceInputType.Select: Interactions[i].BoolData = IsPinching || IsGrabbing; if (Interactions[i].Changed) { if (Interactions[i].BoolData) { CoreServices.InputSystem?.RaiseOnInputDown(InputSource, ControllerHandedness, Interactions[i].MixedRealityInputAction); } else { CoreServices.InputSystem?.RaiseOnInputUp(InputSource, ControllerHandedness, Interactions[i].MixedRealityInputAction); } } break; case DeviceInputType.TriggerPress: case DeviceInputType.GripPress: Interactions[i].BoolData = IsPinching || IsGrabbing; if (Interactions[i].Changed) { if (Interactions[i].BoolData) { CoreServices.InputSystem?.RaiseOnInputDown(InputSource, ControllerHandedness, Interactions[i].MixedRealityInputAction); } else { CoreServices.InputSystem?.RaiseOnInputUp(InputSource, ControllerHandedness, Interactions[i].MixedRealityInputAction); } } break; case DeviceInputType.IndexFinger: HandDefinition.UpdateCurrentIndexPose(Interactions[i]); break; case DeviceInputType.ThumbStick: HandDefinition.UpdateCurrentTeleportPose(Interactions[i]); break; } } }