Example #1
0
        /// <summary>
        /// Writes the desired rotation values for each joint based on the provided SnapAddress.
        /// Apart from the rotations it also writes in the syntheticHand if it should allow rotations
        /// past that.
        /// When no snap is provided, it frees all fingers allowing unconstrained tracked motion.
        /// </summary>
        private void UpdateFingers(HandPose handPose, HandFingerFlags grabbingFingers, float strength)
        {
            Quaternion[] desiredRotations = handPose.JointRotations;
            _syntheticHand.OverrideAllJoints(desiredRotations, strength);

            for (int fingerIndex = 0; fingerIndex < Constants.NUM_FINGERS; fingerIndex++)
            {
                int          fingerFlag    = 1 << fingerIndex;
                JointFreedom fingerFreedom = handPose.FingersFreedom[fingerIndex];
                if (fingerFreedom == JointFreedom.Constrained &&
                    ((int)grabbingFingers & fingerFlag) != 0)
                {
                    fingerFreedom = JointFreedom.Locked;
                }
                _syntheticHand.SetFingerFreedom((HandFinger)fingerIndex, fingerFreedom);
            }
        }
Example #2
0
        private Rect DrawFingersFreedomMenu(SerializedProperty property, Rect position)
        {
            _foldedFreedom = EditorGUI.Foldout(position, _foldedFreedom, "Fingers Freedom", true);
            position.y    += EditorConstants.ROW_HEIGHT;
            if (_foldedFreedom)
            {
                SerializedProperty fingersFreedom = property.FindPropertyRelative("_fingersFreedom");
                EditorGUI.indentLevel++;
                for (int i = 0; i < Constants.NUM_FINGERS; i++)
                {
                    SerializedProperty finger   = fingersFreedom.GetArrayElementAtIndex(i);
                    HandFinger         fingerID = (HandFinger)i;
                    JointFreedom       current  = (JointFreedom)finger.intValue;
                    JointFreedom       selected = (JointFreedom)EditorGUI.EnumPopup(position, $"{fingerID}: ", current);
                    finger.intValue = (int)selected;
                    position.y     += EditorConstants.ROW_HEIGHT;
                }
                EditorGUI.indentLevel--;
            }

            return(position);
        }
Example #3
0
        /// <summary>
        /// Updates the rotation of the joints in the hand
        /// using the visual provided values. Sometimes this
        /// might require lerping between the tracked pose
        /// and the provided ones to improve the movement of the fingers
        /// without worrying about when the overwrite values were written.
        ///
        /// During this update the modifier also ensures that fingers that disallow
        /// some movement (locked or constrained) have their values properly set, and
        /// when there is an unlock event the finger values are smoothly animated back to
        /// their tracked rotations.
        /// </summary>
        /// <param name="data">The entire hand data structure to read and write the joints rotations from</param>
        private void UpdateJointsRotation(HandDataAsset data)
        {
            float extraRotationAllowance = 0f;

            Quaternion[] jointRotations = data.Joints;

            for (int i = 0; i < FingersMetadata.HAND_JOINT_IDS.Length; ++i)
            {
                JointFreedom freedomLevel    = _jointsFreedomLevels[i];
                Quaternion   desiredRotation = _desiredJointsRotation[i];
                float        overrideFactor  = _jointsOverrideFactor[i];
                int          rawJointIndex   = (int)FingersMetadata.HAND_JOINT_IDS[i];

                if (freedomLevel == JointFreedom.Free)
                {
                    //nothing to do, we move the finger freely
                }
                else if (freedomLevel == JointFreedom.Locked)
                {
                    jointRotations[rawJointIndex] = Quaternion.Slerp(
                        jointRotations[rawJointIndex],
                        desiredRotation,
                        overrideFactor);
                }
                else if (freedomLevel == JointFreedom.Constrained)
                {
                    bool jointCanSpread = false;
                    if (FingersMetadata.HAND_JOINT_CAN_SPREAD[i])
                    {
                        jointCanSpread         = true;
                        extraRotationAllowance = 0f;
                    }

                    Quaternion maxRotation = desiredRotation * Quaternion.Euler(0f, 0f, -90f * extraRotationAllowance);

                    float overRotation = OverFlex(jointRotations[rawJointIndex], maxRotation);
                    extraRotationAllowance = Mathf.Max(extraRotationAllowance, overRotation);

                    if (overRotation < 0f)
                    {
                        jointRotations[rawJointIndex] = Quaternion.Slerp(
                            jointRotations[rawJointIndex],
                            maxRotation,
                            overrideFactor);
                    }
                    else if (jointCanSpread)
                    {
                        Quaternion trackedRotation = jointRotations[rawJointIndex];
                        float      spreadAngle     = Vector3.SignedAngle(
                            trackedRotation * Vector3.forward,
                            maxRotation * Vector3.forward,
                            trackedRotation * Vector3.up);

                        float spreadFactor = 1f - Mathf.Clamp01(overRotation * _spreadAllowance);
                        trackedRotation = trackedRotation * Quaternion.Euler(0f, spreadAngle * spreadFactor, 0f);
                        jointRotations[rawJointIndex] = trackedRotation;
                    }
                }

                float smoothFactor = _jointsFreedomLevels[i] == JointFreedom.Free ?
                                     _jointUnlockProgressCurves[i].Progress()
                    : _jointLockProgressCurves[i].Progress();

                jointRotations[rawJointIndex] = Quaternion.Slerp(
                    _constrainedJointRotations[i],
                    jointRotations[rawJointIndex],
                    smoothFactor);

                _lastSyntheticRotation[i] = jointRotations[rawJointIndex];
            }
        }