/// <summary> /// Forces the given object to be released by any hands currently holding it. Will return true /// only if there was at least one hand holding the object. /// </summary> public bool ReleaseObject(IInteractionBehaviour graspedObject) { if (!_graspedBehaviours.Remove(graspedObject)) { return(false); } foreach (var interactionHand in _idToInteractionHand.Values) { if (interactionHand.graspedObject == graspedObject) { if (interactionHand.isUntracked) { interactionHand.MarkTimeout(); } else { if (_graspingEnabled) { INTERACTION_HAND_RESULT result = new INTERACTION_HAND_RESULT(); result.classification = ManipulatorMode.Contact; result.handFlags = HandResultFlags.ManipulatorMode; result.instanceHandle = new INTERACTION_SHAPE_INSTANCE_HANDLE(); InteractionC.OverrideHandResult(ref _scene, (uint)interactionHand.hand.Id, ref result); } interactionHand.ReleaseObject(); } } } return(true); }
protected virtual INTERACTION_HAND_RESULT getHandResults(InteractionHand hand) { if (!_graspingEnabled) { INTERACTION_HAND_RESULT result = new INTERACTION_HAND_RESULT(); result.classification = ManipulatorMode.Contact; result.handFlags = HandResultFlags.ManipulatorMode; result.instanceHandle = new INTERACTION_SHAPE_INSTANCE_HANDLE(); return(result); } INTERACTION_HAND_RESULT handResult; InteractionC.GetHandResult(ref _scene, (uint)hand.hand.Id, out handResult); return(handResult); }
protected virtual void updateInteractionStateChanges(Frame frame) { var hands = frame.Hands; INTERACTION_HAND_RESULT handResult = new INTERACTION_HAND_RESULT(); //First loop through all the hands and get their classifications from the engine for (int i = 0; i < hands.Count; i++) { Hand hand = hands[i]; bool handResultForced = false; //Get the InteractionHand associated with this hand id InteractionHand interactionHand; if (!_idToInteractionHand.TryGetValue(hand.Id, out interactionHand)) { //First we see if there is an untracked interactionHand that can be re-connected using this one InteractionHand untrackedInteractionHand = null; foreach (var pair in _idToInteractionHand) { //If the old ieHand is untracked, and the handedness matches, we re-connect it if (pair.Value.isUntracked && pair.Value.hand.IsLeft == hand.IsLeft) { untrackedInteractionHand = pair.Value; break; } } if (untrackedInteractionHand != null) { //If we found an untrackedIeHand, use it! interactionHand = untrackedInteractionHand; //Remove the old id from the mapping _idToInteractionHand.Remove(untrackedInteractionHand.hand.Id); _idToInteractionHand[hand.Id] = interactionHand; try { //This also dispatched InteractionObject.OnHandRegainedTracking() interactionHand.RegainTracking(hand); if (interactionHand.graspedObject == null) { continue; } // NotifyHandRegainedTracking() did not throw, continue on to NotifyHandsHoldPhysics(). dispatchOnHandsHolding(hands, interactionHand.graspedObject, isPhysics: true); } catch (Exception e) { _activityManager.NotifyMisbehaving(interactionHand.graspedObject); Debug.LogException(e); continue; } //Override the existing classification to force the hand to grab the old object handResultForced = true; handResult.classification = ManipulatorMode.Grasp; handResult.handFlags = HandResultFlags.ManipulatorMode; handResult.instanceHandle = interactionHand.graspedObject.ShapeInstanceHandle; if (_graspingEnabled) { InteractionC.OverrideHandResult(ref _scene, (uint)hand.Id, ref handResult); } } else { //Otherwise just create a new one interactionHand = new InteractionHand(hand); _idToInteractionHand[hand.Id] = interactionHand; } } if (!handResultForced) { handResult = getHandResults(interactionHand); } interactionHand.UpdateHand(hand); if (!interactionHand.isUserGrasp) { switch (handResult.classification) { case ManipulatorMode.Grasp: { IInteractionBehaviour interactionBehaviour; if (_instanceHandleToBehaviour.TryGetValue(handResult.instanceHandle, out interactionBehaviour)) { if (interactionHand.graspedObject == null) { if (!interactionBehaviour.IsBeingGrasped) { _graspedBehaviours.Add(interactionBehaviour); } try { interactionHand.GraspObject(interactionBehaviour, isUserGrasp: false); //the grasp callback might have caused the object to become ungrasped //the component might have also destroyed itself! if (interactionHand.graspedObject == interactionBehaviour && interactionBehaviour != null) { dispatchOnHandsHolding(hands, interactionBehaviour, isPhysics: true); } } catch (Exception e) { _activityManager.NotifyMisbehaving(interactionBehaviour); Debug.LogException(e); continue; } } } else { Debug.LogError("Recieved a hand result with an unkown handle " + handResult.instanceHandle.handle); } break; } case ManipulatorMode.Contact: { if (interactionHand.graspedObject != null) { if (interactionHand.graspedObject.GraspingHandCount == 1) { _graspedBehaviours.Remove(interactionHand.graspedObject); } try { interactionHand.ReleaseObject(); } catch (Exception e) { _activityManager.NotifyMisbehaving(interactionHand.graspedObject); Debug.LogException(e); continue; } } break; } default: throw new InvalidOperationException("Unexpected classification " + handResult.classification); } } } //Loop through all ieHands to check for timeouts and loss of tracking foreach (var pair in _idToInteractionHand) { var id = pair.Key; var ieHand = pair.Value; float handAge = Time.unscaledTime - ieHand.lastTimeUpdated; //Check to see if the hand is at least 1 frame old //We assume it has become untracked if this is the case if (handAge > 0) { //If the hand isn't grasping anything, just remove it if (ieHand.graspedObject == null) { _handIdsToRemove.Add(id); continue; } //If is isn't already marked as untracked, mark it as untracked if (!ieHand.isUntracked) { try { //This also dispatches InteractionObject.OnHandLostTracking() ieHand.MarkUntracked(); } catch (Exception e) { _activityManager.NotifyMisbehaving(ieHand.graspedObject); Debug.LogException(e); } } //If the age is longer than the timeout, we also remove it from the list if (handAge >= ieHand.maxSuspensionTime) { _handIdsToRemove.Add(id); try { if (ieHand.graspedObject.GraspingHandCount == 1) { _graspedBehaviours.Remove(ieHand.graspedObject); } //This also dispatched InteractionObject.OnHandTimeout() ieHand.MarkTimeout(); } catch (Exception e) { _activityManager.NotifyMisbehaving(ieHand.graspedObject); Debug.LogException(e); } } } } //Loop through the stale ids and remove them from the map for (int i = 0; i < _handIdsToRemove.Count; i++) { _idToInteractionHand.Remove(_handIdsToRemove[i]); } _handIdsToRemove.Clear(); }
/// <summary> /// Forces the given object to be released by any hands currently holding it. Will return true /// only if there was at least one hand holding the object. /// </summary> public bool ReleaseObject(IInteractionBehaviour graspedObject) { if (!_graspedBehaviours.Remove(graspedObject)) { return false; } foreach (var interactionHand in _idToInteractionHand.Values) { if (interactionHand.graspedObject == graspedObject) { if (interactionHand.isUntracked) { interactionHand.MarkTimeout(); } else { if (_graspingEnabled) { INTERACTION_HAND_RESULT result = new INTERACTION_HAND_RESULT(); result.classification = ManipulatorMode.Contact; result.handFlags = HandResultFlags.ManipulatorMode; result.instanceHandle = new INTERACTION_SHAPE_INSTANCE_HANDLE(); InteractionC.OverrideHandResult(ref _scene, (uint)interactionHand.hand.Id, ref result); } interactionHand.ReleaseObject(); } } } return true; }
protected virtual INTERACTION_HAND_RESULT getHandResults(InteractionHand hand) { if (!_graspingEnabled) { INTERACTION_HAND_RESULT result = new INTERACTION_HAND_RESULT(); result.classification = ManipulatorMode.Contact; result.handFlags = HandResultFlags.ManipulatorMode; result.instanceHandle = new INTERACTION_SHAPE_INSTANCE_HANDLE(); return result; } INTERACTION_HAND_RESULT handResult; InteractionC.GetHandResult(ref _scene, (uint)hand.hand.Id, out handResult); return handResult; }