diff --git a/AlternateIKSystem/IK/IKCalibrator.cs b/AlternateIKSystem/IK/IKCalibrator.cs index aff9891..f3cfa7d 100644 --- a/AlternateIKSystem/IK/IKCalibrator.cs +++ b/AlternateIKSystem/IK/IKCalibrator.cs @@ -1,12 +1,13 @@ using RootMotion.FinalIK; using UnityEngine; +using Valve.VR; using Object = UnityEngine.Object; namespace NAK.AlternateIKSystem.IK; internal static class IKCalibrator { - #region VRIK Setup + #region VRIK Solver Setup public static VRIK SetupVrIk(Animator animator) { @@ -183,14 +184,39 @@ internal static class IKCalibrator #endregion - // TODO: figure out proper Desktop & VR organization - public static void SetupHeadIKTargetDesktop(VRIK vrik) + #region VRIK Calibration + + public static void SetupHeadIKTarget(VRIK vrik, Transform parent = null) { + // VR Camera may have Head IK Target from previous avatar + Transform existingTarget = parent?.Find("Head IK Target"); + if (existingTarget != null) + Object.DestroyImmediate(existingTarget.gameObject); + + parent ??= vrik.references.head; + // Lazy HeadIKTarget calibration - if (vrik.solver.spine.headTarget == null) - vrik.solver.spine.headTarget = new GameObject("Head IK Target").transform; - vrik.solver.spine.headTarget.parent = vrik.references.head; - vrik.solver.spine.headTarget.localPosition = Vector3.zero; + vrik.solver.spine.headTarget = new GameObject("Head IK Target").transform; vrik.solver.spine.headTarget.localRotation = Quaternion.identity; + + vrik.solver.spine.headTarget.parent = parent; + vrik.solver.spine.headTarget.localPosition = Vector3.zero; + vrik.solver.spine.headTarget.localScale = Vector3.one; } + + public static void SetupHandIKTarget(VRIK vrik, Transform handOffset, Transform handAnchor, bool isLeft) + { + handAnchor.SetParent(isLeft ? vrik.references.leftHand : vrik.references.rightHand); + handAnchor.localPosition = Vector3.zero; + handAnchor.localRotation = Quaternion.identity; + handAnchor.SetParent(handOffset, true); + handAnchor.localPosition = Vector3.zero; + + if (isLeft) + vrik.solver.leftArm.target = handAnchor; + else + vrik.solver.rightArm.target = handAnchor; + } + + #endregion } \ No newline at end of file diff --git a/AlternateIKSystem/IK/IKHandlers/IKHandler.cs b/AlternateIKSystem/IK/IKHandlers/IKHandler.cs index 5e6a40a..7d54319 100644 --- a/AlternateIKSystem/IK/IKHandlers/IKHandler.cs +++ b/AlternateIKSystem/IK/IKHandlers/IKHandler.cs @@ -41,9 +41,34 @@ internal abstract class IKHandler public virtual void OnInitializeIk() { } - public virtual void OnPlayerScaled(float scaleDifference) { } + public virtual void OnPlayerScaled(float scaleDifference) + { + VRIKUtils.ApplyScaleToVRIK + ( + _vrik, + _locomotionData, + _scaleDifference = scaleDifference + ); + } - public virtual void OnPlayerHandleMovementParent(CVRMovementParent currentParent) { } + public virtual void OnPlayerHandleMovementParent(CVRMovementParent currentParent, Vector3 platformPivot) + { + Vector3 currentPosition = currentParent._referencePoint.position; + Quaternion currentRotation = Quaternion.Euler(0f, currentParent.transform.rotation.eulerAngles.y, 0f); + + Vector3 deltaPosition = currentPosition - _movementPosition; + Quaternion deltaRotation = Quaternion.Inverse(_movementRotation) * currentRotation; + + if (_movementParent == currentParent) + { + _solver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot); + _ikSimulatedRootAngle = Mathf.Repeat(_ikSimulatedRootAngle + deltaRotation.eulerAngles.y, 360f); + } + + _movementParent = currentParent; + _movementPosition = currentPosition; + _movementRotation = currentRotation; + } #endregion diff --git a/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs b/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs index 46b9e2f..2a18ea6 100644 --- a/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs +++ b/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs @@ -29,42 +29,6 @@ internal class IKHandlerDesktop : IKHandler _vrik.onPreSolverUpdate.AddListener(OnPreSolverUpdateDesktop); } - public override void OnPlayerScaled(float scaleDifference) - { - VRIKUtils.ApplyScaleToVRIK - ( - _vrik, - _locomotionData, - _scaleDifference = scaleDifference - ); - } - - public override void OnPlayerHandleMovementParent(CVRMovementParent currentParent) - { - // Get current position - Vector3 currentPosition = currentParent._referencePoint.position; - Quaternion currentRotation = Quaternion.Euler(0f, currentParent.transform.rotation.eulerAngles.y, 0f); - - // Convert to delta position (how much changed since last frame) - Vector3 deltaPosition = currentPosition - _movementPosition; - Quaternion deltaRotation = Quaternion.Inverse(_movementRotation) * currentRotation; - - // Desktop pivots from playerlocal transform - Vector3 platformPivot = IKManager.Instance.transform.position; - - // Prevent targeting other parent position - if (_movementParent == currentParent) - { - _solver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot); - _ikSimulatedRootAngle = Mathf.Repeat(_ikSimulatedRootAngle + deltaRotation.eulerAngles.y, 360f); - } - - // Store for next frame - _movementParent = currentParent; - _movementPosition = currentPosition; - _movementRotation = currentRotation; - } - #endregion #region Weight Overrides @@ -81,57 +45,6 @@ internal class IKHandlerDesktop : IKHandler _solver.spine.positionWeight = 0f; } - protected override void Update_HeadWeight() - { - float targetWeight = GetTargetWeight(BodyControl.TrackingHead, true); - BodyControl.SetHeadWeight(_solver.spine, targetWeight); - BodyControl.SetLookAtWeight(IKManager.lookAtIk, targetWeight); - } - - protected override void Update_LeftArmWeight() - { - float leftArmWeight = GetTargetWeight(BodyControl.TrackingLeftArm, _solver.leftArm.target != null); - BodyControl.SetArmWeight(_solver.leftArm, leftArmWeight); - } - - protected override void Update_RightArmWeight() - { - float rightArmWeight = GetTargetWeight(BodyControl.TrackingRightArm, _solver.rightArm.target != null); - BodyControl.SetArmWeight(_solver.rightArm, rightArmWeight); - } - - protected override void Update_LeftLegWeight() - { - float leftLegWeight = GetTargetWeight(BodyControl.TrackingLeftLeg, _solver.leftLeg.target != null); - BodyControl.SetLegWeight(_solver.leftLeg, leftLegWeight); - } - - protected override void Update_RightLegWeight() - { - float rightLegWeight = GetTargetWeight(BodyControl.TrackingRightLeg, _solver.rightLeg.target != null); - BodyControl.SetLegWeight(_solver.rightLeg, rightLegWeight); - } - - protected override void Update_PelvisWeight() - { - float pelvisWeight = GetTargetWeight(BodyControl.TrackingPelvis, _solver.spine.pelvisTarget != null); - BodyControl.SetPelvisWeight(_solver.spine, pelvisWeight); - } - - protected override void Update_LocomotionWeight() - { - _locomotionWeight = Mathf.Lerp(_locomotionWeight, BodyControl.TrackingLocomotion ? 1f : 0f, - Time.deltaTime * ModSettings.EntryIKLerpSpeed.Value * 2f); - BodyControl.SetLocomotionWeight(_solver.locomotion, _locomotionWeight); - } - - protected override void Update_IKPositionWeight() - { - float ikPositionWeight = BodyControl.TrackingAll ? BodyControl.TrackingIKPositionWeight : 0f; - BodyControl.SetIKPositionWeight(_solver, ikPositionWeight); - BodyControl.SetIKPositionWeight(IKManager.lookAtIk, ikPositionWeight); - } - #endregion #region VRIK Solver Events diff --git a/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs b/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs index d94ecdb..90f6783 100644 --- a/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs +++ b/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs @@ -25,42 +25,33 @@ internal class IKHandlerHalfBody : IKHandler shouldTrackRightLeg = false; shouldTrackPelvis = false; shouldTrackLocomotion = true; + + _vrik.onPreSolverUpdate.AddListener(OnPreSolverUpdateHalfBody); } + + #endregion - public override void OnPlayerScaled(float scaleDifference) + #region VRIK Solver Events + + private void OnPreSolverUpdateHalfBody() { - VRIKUtils.ApplyScaleToVRIK - ( - _vrik, - _locomotionData, - _scaleDifference = scaleDifference - ); - } + _solver.plantFeet = ModSettings.EntryPlantFeet.Value; - public override void OnPlayerHandleMovementParent(CVRMovementParent currentParent) - { - // Get current position - Vector3 currentPosition = currentParent._referencePoint.position; - Quaternion currentRotation = Quaternion.Euler(0f, currentParent.transform.rotation.eulerAngles.y, 0f); - - // Convert to delta position (how much changed since last frame) - Vector3 deltaPosition = currentPosition - _movementPosition; - Quaternion deltaRotation = Quaternion.Inverse(_movementRotation) * currentRotation; - - // Desktop pivots from playerlocal transform - Vector3 platformPivot = IKManager.Instance.transform.position; - - // Prevent targeting other parent position - if (_movementParent == currentParent) + // Make root heading follow within a set limit + if (ModSettings.EntryBodyHeadingLimit.Value > 0) { - _solver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot); - _ikSimulatedRootAngle = Mathf.Repeat(_ikSimulatedRootAngle + deltaRotation.eulerAngles.y, 360f); - } + float weightedAngleLimit = ModSettings.EntryBodyHeadingLimit.Value * _solver.locomotion.weight; + float currentRotation = IKManager.Instance.GetPlayerRotation().y; + float deltaAngleRoot = Mathf.DeltaAngle(currentRotation, _ikSimulatedRootAngle); - // Store for next frame - _movementParent = currentParent; - _movementPosition = currentPosition; - _movementRotation = currentRotation; + if (Mathf.Abs(deltaAngleRoot) > weightedAngleLimit) + { + deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit; + _ikSimulatedRootAngle = Mathf.MoveTowardsAngle(_ikSimulatedRootAngle, currentRotation, Mathf.Abs(deltaAngleRoot) - weightedAngleLimit); + } + + _solver.spine.rootHeadingOffset = deltaAngleRoot; + } } #endregion diff --git a/AlternateIKSystem/IK/IKManager.cs b/AlternateIKSystem/IK/IKManager.cs index 0a8b15e..35f86c2 100644 --- a/AlternateIKSystem/IK/IKManager.cs +++ b/AlternateIKSystem/IK/IKManager.cs @@ -6,6 +6,7 @@ using NAK.AlternateIKSystem.VRIKHelpers; using RootMotion.FinalIK; using UnityEngine; using UnityEngine.Events; +using Object = System.Object; namespace NAK.AlternateIKSystem.IK; @@ -32,6 +33,18 @@ public class IKManager : MonoBehaviour internal Transform _desktopCamera; internal Transform _vrCamera; + // Controller Info + private Transform _leftController; + private Transform _rightController; + private Transform _leftHandTarget; + private Transform _leftHandRotations; + private Transform _rightHandTarget; + private Transform _rightHandRotations; + + // Hand Anchor Offsets + private Vector3 _handAnchorPositionOffset = new Vector3(-0.038f, 0.0389f, -0.138f); + private Vector3 _handAnchorRotationOffset = Vector3.zero; + // Avatar Info private Animator _animator; private Transform _hipTransform; @@ -39,6 +52,8 @@ public class IKManager : MonoBehaviour // Animator Info private int _animLocomotionLayer = -1; private int _animIKPoseLayer = -1; + private const string _locomotionLayerName = "Locomotion/Emotes"; + private const string _ikposeLayerName = "IKPose"; // Pose Info private HumanPoseHandler _humanPoseHandler; @@ -60,8 +75,16 @@ public class IKManager : MonoBehaviour _desktopCamera = PlayerSetup.Instance.desktopCamera.transform; _vrCamera = PlayerSetup.Instance.vrCamera.transform; - } + _leftController = PlayerSetup.Instance.vrLeftHandTracker.transform; + _rightController = PlayerSetup.Instance.vrRightHandTracker.transform; + // ouchie + _leftHandTarget = _leftController.Find("LeftHandTarget"); + _leftHandRotations = _leftHandTarget.Find("LeftHandRotations"); + _rightHandTarget = _rightController.Find("RightHandTarget"); + _rightHandRotations = _rightHandTarget.Find("RightHandRotations"); + } + private void Update() { BodyControl.Update(); @@ -91,8 +114,8 @@ public class IKManager : MonoBehaviour _animator.cullingMode = AnimatorCullingMode.AlwaysAnimate; - _animIKPoseLayer = _animator.GetLayerIndex("IKPose"); - _animLocomotionLayer = _animator.GetLayerIndex("Locomotion/Emotes"); + _animIKPoseLayer = _animator.GetLayerIndex(_ikposeLayerName); + _animLocomotionLayer = _animator.GetLayerIndex(_locomotionLayerName); _hipTransform = _animator.GetBoneTransform(HumanBodyBones.Hips); @@ -160,7 +183,7 @@ public class IKManager : MonoBehaviour if (!_isAvatarInitialized) return false; - _ikHandler?.OnPlayerHandleMovementParent(movementParent); + _ikHandler?.OnPlayerHandleMovementParent(movementParent, GetPlayerPosition()); return true; } @@ -184,7 +207,7 @@ public class IKManager : MonoBehaviour IKCalibrator.ConfigureDesktopVrIk(_vrik); _ikHandler = new IKHandlerDesktop(_vrik); - IKCalibrator.SetupHeadIKTargetDesktop(_vrik); + IKCalibrator.SetupHeadIKTarget(_vrik); InitializeIkGeneral(); @@ -197,7 +220,17 @@ public class IKManager : MonoBehaviour IKCalibrator.ConfigureHalfBodyVrIk(_vrik); _ikHandler = new IKHandlerHalfBody(_vrik); + + IKCalibrator.SetupHeadIKTarget(_vrik, _vrCamera); + IKCalibrator.SetupHandIKTarget(_vrik, _leftHandTarget, _leftHandRotations, true); + IKCalibrator.SetupHandIKTarget(_vrik, _rightHandTarget, _rightHandRotations, false); + // Configure controller offsets + _leftHandTarget.localPosition = _handAnchorPositionOffset; + _leftHandTarget.localEulerAngles = _handAnchorRotationOffset; + _rightHandTarget.localPosition = Vector3.Scale(_handAnchorPositionOffset, new Vector3(-1, 1, 1)); + _rightHandTarget.localEulerAngles = Vector3.Scale(_handAnchorRotationOffset, new Vector3(1, -1, -1)); + InitializeIkGeneral(); _ikHandler.OnInitializeIk(); @@ -226,6 +259,30 @@ public class IKManager : MonoBehaviour #endregion + #region Public Methods + + public Vector3 GetPlayerPosition() + { + if (!MetaPort.Instance.isUsingVr) + return transform.position; + + Vector3 vrPosition = _vrCamera.transform.position; + vrPosition.y = transform.position.y; + return vrPosition; + } + + public Quaternion GetPlayerRotation() + { + if (!MetaPort.Instance.isUsingVr) + return transform.rotation; + + Vector3 vrForward = _vrCamera.transform.forward; + vrForward.y = 0f; + return Quaternion.LookRotation(vrForward, Vector3.up); + } + + #endregion + #region VRIK Solver Events General private void OnPreSolverUpdateGeneral()