/// <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); } }
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); }
/// <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]; } }