//Loops:
 private void Update()
 {
     if (!_isMine)
     {
         transform.position   = Vector3.SmoothDamp(transform.position, _targetPosition, ref _positionVelocity, smoothTime);
         transform.rotation   = MotionUtilities.SmoothDamp(transform.rotation, _targetRotation, ref _rotationVelocity, smoothTime);
         transform.localScale = Vector3.SmoothDamp(transform.localScale, targetScale, ref _scaleVelocity, smoothTime);
     }
 }
Example #2
0
        //Coroutines:
        private IEnumerator TweenPose()
        {
            while (Quaternion.Angle(transform.rotation, _targetRotation) > 0)
            {
                transform.position = Vector3.SmoothDamp(transform.position, _targetPosition, ref _positionalVelocity, _smoothTime);
                transform.rotation = MotionUtilities.SmoothDamp(transform.rotation, _targetRotation, ref _rotationalVelocity, _smoothTime);

                yield return(null);
            }
        }
 //Loops:
 private void LateUpdate()
 {
     if (!_isMine)
     {
         transform.localPosition = Vector3.SmoothDamp(transform.localPosition, targetPosition, ref _positionaVelocity, smoothTime);
         transform.localRotation = MotionUtilities.SmoothDamp(transform.localRotation, targetRotation, ref _rotationVelocity, smoothTime);
         transform.localScale    = Vector3.SmoothDamp(transform.localScale, targetScale, ref _scaleVelocity, smoothTime);
     }
     else
     {
         //automatically follow motion source if set:
         if (motionSource != null)
         {
             transform.position   = motionSource.position;
             transform.rotation   = motionSource.rotation;
             transform.localScale = motionSource.localScale;
         }
     }
 }
        //Loops:
        private void LateUpdate()
        {
            //remove any negative durations:
            arrivalDuration = Mathf.Max(0, arrivalDuration);

            //direction:
            _direction = Vector3.Normalize(transform.position - _mainCamera.position);
            if (_direction == Vector3.zero)
            {
                return;
            }

            //match gravity?
            if (matchGravity)
            {
                _direction = Vector3.ProjectOnPlane(_direction, Vector3.up);
            }

            //flipped?
            if (flippedForward)
            {
                _direction *= -1;
            }

            //get rotation:
            if (_direction != Vector3.zero)
            {
                _rotation = Quaternion.LookRotation(_direction);
            }

            //apply:
            if (Application.isPlaying)
            {
                transform.rotation = MotionUtilities.SmoothDamp(transform.rotation, _rotation, ref _velocity, arrivalDuration);
            }
            else
            {
                //time doesn't update smoothly while not playing in the editor so let's just force snapping:
                transform.rotation = _rotation;
            }
        }
Example #5
0
 //Loops:
 private void Update()
 {
     //lerp us to the world-aligned location:
     transform.position = Vector3.SmoothDamp(transform.position, _targetPosition, ref _positionalVelocity, _smoothTime);
     transform.rotation = MotionUtilities.SmoothDamp(transform.rotation, _targetRotation, ref _rotationalVelocity, _smoothTime);
 }
        //Public Methods:
        public void Update()
        {
            if (!_managedHand.Visible)
            {
                return;
            }

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

            if (_managedHand.Hand.Type == MLHandTracking.HandType.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 == MLHandTracking.HandKeyPose.C || _managedHand.Hand.KeyPose == MLHandTracking.HandKeyPose.OpenHand || _managedHand.Hand.KeyPose == MLHandTracking.HandKeyPose.L || _managedHand.Hand.KeyPose == MLHandTracking.HandKeyPose.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 == MLHandTracking.HandKeyPose.Finger || _managedHand.Hand.KeyPose == MLHandTracking.HandKeyPose.L)
                                {
                                    Intent = IntentPose.Pointing;
                                    OnIntentChanged?.Invoke(_managedHand, Intent);
                                }
                                else if (_managedHand.Hand.KeyPose == MLHandTracking.HandKeyPose.C || _managedHand.Hand.KeyPose == MLHandTracking.HandKeyPose.OpenHand || _managedHand.Hand.KeyPose == MLHandTracking.HandKeyPose.Thumb)
                                {
                                    Intent = IntentPose.Relaxed;
                                    OnIntentChanged?.Invoke(_managedHand, Intent);
                                }
                            }
                        }
                    }
                }
                else
                {
                    //intent begin:
                    if (_managedHand.Hand.KeyPose == MLHandTracking.HandKeyPose.Pinch || _managedHand.Hand.KeyPose == MLHandTracking.HandKeyPose.Ok || _managedHand.Hand.KeyPose == MLHandTracking.HandKeyPose.Fist)
                    {
                        _collapsed = true;

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

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

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

            UpdateCurrentInteractionPoint();
            UpdatePalmEvents();
        }
Example #7
0
        public void GrabUpdate(InteractionPoint interactionPoint)
        {
            //dragging started?
            if (!Dragging)
            {
                foreach (var item in _initialInteractionPoses)
                {
                    if (Vector3.Distance(item.Key.position, item.Value.position) > _dragThreshold)
                    {
                        //halt physics:
                        if (_rigidBody != null)
                        {
                            _rigidBody.velocity        = Vector3.zero;
                            _rigidBody.angularVelocity = Vector3.zero;
                            _rigidBody.isKinematic     = true;
                        }

                        //find offset:
                        Matrix4x4  matrix         = Matrix4x4.TRS(item.Key.position, item.Key.rotation, Vector3.one);
                        Vector3    positionOffset = matrix.inverse.MultiplyPoint3x4(transform.position);
                        Quaternion rotationOffset = Quaternion.Inverse(item.Key.rotation) * transform.rotation;
                        _offset = new Pose(positionOffset, rotationOffset);

                        //resets:
                        _position = Vector3.zero;
                        _rotation = Quaternion.identity;

                        //status:
                        Dragging = true;
                        OnDragBegin?.Invoke(item.Key);
                        break;
                    }
                }
            }

            //dragging?
            if (Dragging)
            {
                //find center of interaction points involved with this drag:
                Bounds dragBounds = new Bounds(activeInteractionPoints[0].position, Vector3.zero);
                for (int i = 1; i < activeInteractionPoints.Count; i++)
                {
                    dragBounds.Encapsulate(activeInteractionPoints[i].position);
                }

                //discover drag distance and percentage;
                float biManualDistance = dragBounds.size.magnitude;

                //holders:
                Vector3    dragLocation    = Vector3.zero;
                Quaternion dragOrientation = Quaternion.identity;
                Vector3    forward         = Vector3.zero;
                float      scaleDelta      = 0;

                //rotation:
                if (activeInteractionPoints.Count == 2)
                {
                    //get rotated amount:
                    forward = activeInteractionPoints[0].position - activeInteractionPoints[1].position;
                    Vector3 forwardNormalized = forward.normalized;
                    Vector3 previousForward   = _bimanualBaseRotation * Vector3.forward;
                    Vector3 up    = Vector3.Cross(forwardNormalized, previousForward).normalized;
                    float   angle = Vector3.SignedAngle(previousForward, forwardNormalized, up);

                    //update rotation:
                    Quaternion rotationDelta = Quaternion.AngleAxis(angle, up);
                    _bimanualBaseRotation = rotationDelta * _bimanualBaseRotation;
                    dragOrientation       = _bimanualBaseRotation * _offset.rotation;
                }
                else
                {
                    dragOrientation = activeInteractionPoints[0].rotation * _offset.rotation;
                }

                //position:
                if (activeInteractionPoints.Count == 2)
                {
                    Matrix4x4 matrix = Matrix4x4.TRS(dragBounds.center, _bimanualBaseRotation, Vector3.one);
                    dragLocation = matrix.MultiplyPoint3x4(_offset.position);
                }
                else
                {
                    Matrix4x4 matrix = Matrix4x4.TRS(activeInteractionPoints[0].position, activeInteractionPoints[0].rotation, Vector3.one);
                    dragLocation = matrix.MultiplyPoint3x4(_offset.position);
                }

                //scale:
                if (activeInteractionPoints.Count == 2)
                {
                    scaleDelta = biManualDistance - _scaleInitialDistance;
                }

                //set smoothing origins:
                if (_position == Vector3.zero || _rotation == Quaternion.identity)
                {
                    _position = dragLocation;
                    _rotation = dragOrientation;
                }

                //application:
                if (draggable)
                {
                    _position = Vector3.SmoothDamp(_position, dragLocation, ref _positionVelocity, positionSmoothTime);
                    if (_rigidBody != null)
                    {
                        _rigidBody.MovePosition(_position);
                        _averageVelocity.Add(_rigidBody.velocity);
                        _averageAngularVelocity.Add(_rigidBody.angularVelocity);
                    }
                    else
                    {
                        transform.position = _position;
                    }
                }

                if (rotatable)
                {
                    _rotation = MotionUtilities.SmoothDamp(_rotation, dragOrientation, ref _rotationVelocity, rotationSmoothTime);
                    if (_rigidBody != null)
                    {
                        _rigidBody.MoveRotation(_rotation);
                    }
                    else
                    {
                        transform.rotation = _rotation;
                    }
                }

                if (scalable && activeInteractionPoints.Count == 2)
                {
                    Vector3 proposedScale = _scaleBase + (Vector3.one * scaleDelta);

                    //constrain scale and do not not assume uniform initial scale:
                    if (Mathf.Max(proposedScale.x, proposedScale.y, proposedScale.z) <= maxScale &&
                        Mathf.Min(proposedScale.x, proposedScale.y, proposedScale.z) >= minScale)
                    {
                        transform.localScale = _scaleBase + (Vector3.one * scaleDelta);
                    }
                }

                //visuals:
                if (activeInteractionPoints.Count == 2)
                {
                    Lines.SetVisibility(_handConnectionLine, true);
                    Lines.DrawLine(_handConnectionLine, Color.cyan, Color.cyan, .0005f, activeInteractionPoints[0].position, activeInteractionPoints[1].position);
                }

                //status:
                OnDragUpdate?.Invoke(activeInteractionPoints.ToArray(), _position, _rotation, scaleDelta);
            }
        }