示例#1
0
    //Public Methods:
    public void Update()
    {
        if (!_managedHand.Visible)
        {
            return;
        }

        //pinch rotation offset mirror:
        Vector3 rotationOffset = _pinchAbsoluteRotationOffset;

        if (_managedHand.Hand.HandType == MLHandType.Left)
        {
            rotationOffset.y *= -1;
        }

        //holders:
        Vector3    pinchPosition = Vector3.zero;
        Quaternion pinchRotation = Quaternion.identity;

        //pinch interaction point radius:
        if (_managedHand.Skeleton.Thumb.Tip.Visible && _managedHand.Skeleton.Index.Tip.Visible)
        {
            Pinch.radius = Vector3.Distance(_managedHand.Skeleton.Thumb.Tip.positionFiltered, _managedHand.Skeleton.Index.Tip.positionFiltered);
        }

        if (_managedHand.Skeleton.Thumb.Tip.Visible) //absolute placement:
        {
            //are we swapping modes?
            if (_pinchIsRelative)
            {
                _pinchIsRelative          = false;
                _pinchTransitioning       = true;
                _pinchTransitionStartTime = Time.realtimeSinceStartup;
            }

            pinchPosition = _managedHand.Skeleton.Thumb.Tip.positionFiltered;
            pinchRotation = TransformUtilities.RotateQuaternion(_managedHand.Skeleton.Rotation, rotationOffset);

            //gather offset distance:
            if (_managedHand.Skeleton.Index.Knuckle.Visible && _managedHand.Skeleton.Thumb.Knuckle.Visible)
            {
                Vector3 mcpMidpoint = Vector3.Lerp(_managedHand.Skeleton.Index.Knuckle.positionFiltered, _managedHand.Skeleton.Thumb.Knuckle.positionFiltered, .5f);
                _pinchRelativePositionDistance = Vector3.Distance(mcpMidpoint, pinchPosition);
            }
        }
        else //relative placement:
        {
            //are we swapping modes?
            if (!_pinchIsRelative)
            {
                _pinchIsRelative          = true;
                _pinchTransitioning       = true;
                _pinchTransitionStartTime = Time.realtimeSinceStartup;
            }

            //place between available mcps:
            if (_managedHand.Skeleton.Index.Knuckle.Visible && _managedHand.Skeleton.Thumb.Knuckle.Visible)
            {
                pinchPosition = Vector3.Lerp(_managedHand.Skeleton.Index.Knuckle.positionFiltered, _managedHand.Skeleton.Thumb.Knuckle.positionFiltered, .5f);

                //rotate:
                pinchRotation = TransformUtilities.RotateQuaternion(_managedHand.Skeleton.Rotation, _pinchRelativeRotationOffset);

                //move out along rotation forward:
                pinchPosition += pinchRotation * Vector3.forward * _pinchRelativePositionDistance;
            }
            else
            {
                //just use previous:
                pinchPosition = Pinch.position;
                pinchRotation = Pinch.rotation;
            }
        }

        //sticky release reduction:
        if (_collapsed)
        {
            if (_managedHand.Skeleton.Thumb.Tip.Visible && _managedHand.Skeleton.Index.Tip.Visible)
            {
                //if starting to release, start using a point between the thumb and index tips:
                if (Vector3.Distance(_managedHand.Skeleton.Thumb.Tip.positionFiltered, _managedHand.Skeleton.Index.Tip.positionFiltered) > _dynamicReleaseDistance)
                {
                    pinchPosition = Vector3.Lerp(_managedHand.Skeleton.Thumb.Tip.positionFiltered, _managedHand.Skeleton.Index.Tip.positionFiltered, .3f);
                }
            }
        }

        //apply pinch pose - to avoid jumps when relative placement is used we smooth until close enough:
        if (_pinchTransitioning)
        {
            //position:
            Pinch.position = Vector3.SmoothDamp(Pinch.position, pinchPosition, ref _pinchArrivalPositionVelocity, _pinchTransitionTime);
            float positionDelta = Vector3.Distance(Pinch.position, pinchPosition);

            //rotation:
            Pinch.rotation = MotionUtilities.SmoothDamp(Pinch.rotation, pinchRotation, ref _pinchArrivalRotationVelocity, _pinchTransitionTime);
            float rotationDelta = Quaternion.Angle(Pinch.rotation, pinchRotation);

            //close enough to hand off?
            if (positionDelta < .001f && rotationDelta < 5)
            {
                _pinchTransitioning = false;
            }

            //taking too long?
            if (Time.realtimeSinceStartup - _pinchTransitionStartTime > _pinchTransitionMaxDuration)
            {
                _pinchTransitioning = false;
            }
        }
        else
        {
            Pinch.position = pinchPosition;
            Pinch.rotation = pinchRotation;
        }

        //grasp interaction point:
        Bounds graspBounds = CalculateGraspBounds
                             (
            _managedHand.Skeleton.Thumb.Knuckle,
            _managedHand.Skeleton.Thumb.Joint,
            _managedHand.Skeleton.Thumb.Tip,
            _managedHand.Skeleton.Index.Knuckle,
            _managedHand.Skeleton.Index.Joint,
            _managedHand.Skeleton.Index.Tip,
            _managedHand.Skeleton.Middle.Knuckle,
            _managedHand.Skeleton.Middle.Joint,
            _managedHand.Skeleton.Middle.Tip
                             );

        Grasp.position = _managedHand.Skeleton.Position;
        //when points are being initially found they can be wildly off and this could cause a massively large volume:
        Grasp.radius   = Mathf.Min(graspBounds.size.magnitude, _maxGraspRadius);
        Grasp.rotation = _managedHand.Skeleton.Rotation;

        //intent updated:
        if (_currentInteractionState != null)
        {
            _currentInteractionState.FireUpdate();
        }

        //keypose change proposed:
        if (_managedHand.Hand.KeyPose != VerifiedGesture && _managedHand.Hand.KeyPose != _proposedKeyPose)
        {
            //queue a new proposed change to keypose:
            _proposedKeyPose    = _managedHand.Hand.KeyPose;
            _keyPoseChangedTime = Time.realtimeSinceStartup;
        }

        //keypose change acceptance:
        if (_managedHand.Hand.KeyPose != VerifiedGesture && Time.realtimeSinceStartup - _keyPoseChangedTime > _keyPoseStabailityDuration)
        {
            //reset:
            Point.active = false;
            Pinch.active = false;
            Grasp.active = false;

            if (_collapsed)
            {
                //intent end:
                if (_managedHand.Hand.KeyPose == MLHandKeyPose.C || _managedHand.Hand.KeyPose == MLHandKeyPose.OpenHand || _managedHand.Hand.KeyPose == MLHandKeyPose.L || _managedHand.Hand.KeyPose == MLHandKeyPose.Finger)
                {
                    if (_managedHand.Skeleton.Thumb.Tip.Visible && _managedHand.Skeleton.Index.Tip.Visible)
                    {
                        //dynamic release:
                        if (Vector3.Distance(_managedHand.Skeleton.Thumb.Tip.positionFiltered, _managedHand.Skeleton.Index.Tip.positionFiltered) > _dynamicReleaseDistance)
                        {
                            //end intent:
                            _collapsed = false;
                            _currentInteractionState.FireEnd();
                            _currentInteractionState = null;

                            //accept keypose change:
                            VerifiedGesture  = _managedHand.Hand.KeyPose;
                            _proposedKeyPose = _managedHand.Hand.KeyPose;
                            OnVerifiedGestureChanged?.Invoke(_managedHand, VerifiedGesture);

                            if (_managedHand.Hand.KeyPose == MLHandKeyPose.Finger || _managedHand.Hand.KeyPose == MLHandKeyPose.L)
                            {
                                Intent = IntentPose.Pointing;
                                OnIntentChanged?.Invoke(_managedHand, Intent);
                            }
                            else if (_managedHand.Hand.KeyPose == MLHandKeyPose.C || _managedHand.Hand.KeyPose == MLHandKeyPose.OpenHand || _managedHand.Hand.KeyPose == MLHandKeyPose.Thumb)
                            {
                                Intent = IntentPose.Relaxed;
                                OnIntentChanged?.Invoke(_managedHand, Intent);
                            }
                        }
                    }
                }
            }
            else
            {
                //intent begin:
                if (_managedHand.Hand.KeyPose == MLHandKeyPose.Pinch || _managedHand.Hand.KeyPose == MLHandKeyPose.Ok || _managedHand.Hand.KeyPose == MLHandKeyPose.Fist)
                {
                    _collapsed = true;

                    if (_managedHand.Hand.KeyPose == MLHandKeyPose.Pinch || _managedHand.Hand.KeyPose == MLHandKeyPose.Ok)
                    {
                        Intent                   = IntentPose.Pinching;
                        Pinch.active             = true;
                        _currentInteractionState = Pinch.Touch;
                        _currentInteractionState.FireBegin();
                        OnIntentChanged?.Invoke(_managedHand, Intent);
                    }
                    else if (_managedHand.Hand.KeyPose == MLHandKeyPose.Fist)
                    {
                        Intent                   = IntentPose.Grasping;
                        Grasp.active             = true;
                        _currentInteractionState = Grasp.Touch;
                        _currentInteractionState.FireBegin();
                        OnIntentChanged?.Invoke(_managedHand, Intent);
                    }
                }

                if (_managedHand.Hand.KeyPose == MLHandKeyPose.Finger || _managedHand.Hand.KeyPose == MLHandKeyPose.L)
                {
                    Intent       = IntentPose.Pointing;
                    Point.active = true;
                    OnIntentChanged?.Invoke(_managedHand, Intent);
                }
                else if (_managedHand.Hand.KeyPose == MLHandKeyPose.C || _managedHand.Hand.KeyPose == MLHandKeyPose.OpenHand || _managedHand.Hand.KeyPose == MLHandKeyPose.Thumb)
                {
                    Intent = IntentPose.Relaxed;
                    OnIntentChanged?.Invoke(_managedHand, Intent);
                }

                //accept keypose change:
                VerifiedGesture  = _managedHand.Hand.KeyPose;
                _proposedKeyPose = _managedHand.Hand.KeyPose;
                OnVerifiedGestureChanged?.Invoke(_managedHand, VerifiedGesture);
            }
        }
    }