diff --git a/AlternateIKSystem/IK/BodyControl.cs b/AlternateIKSystem/IK/BodyControl.cs index df9767f..0fb517a 100644 --- a/AlternateIKSystem/IK/BodyControl.cs +++ b/AlternateIKSystem/IK/BodyControl.cs @@ -33,7 +33,7 @@ public class BodyControl public static bool TrackingLeftLeg = true; public static bool TrackingRightLeg = true; public static bool TrackingLocomotion = true; - public static float TrackingPositionWeight = 1f; + public static float TrackingIKPositionWeight = 1f; // TODO: decide if this is considered "Tracking Controls" public static float TrackingMaxRootAngle = 0f; @@ -52,6 +52,8 @@ public class BodyControl #endregion + #region Public Methods + public void Update() { TrackingAll = ShouldTrackAll(); @@ -59,6 +61,8 @@ public class BodyControl AvatarUpright = GetPlayerUpright(); } + #endregion + #region Private Methods private static bool ShouldTrackAll() @@ -87,20 +91,26 @@ public class BodyControl #region Solver Weight Helpers - public static void SetHeadWeight(IKSolverVR.Spine spine, LookAtIK lookAtIk, float weight) + // I am unsure on this...? + + public static void SetLookAtWeight(LookAtIK lookAtIk, float weight) + { + if (lookAtIk != null) + lookAtIk.solver.IKPositionWeight = weight; + } + + public static void SetHeadWeight(IKSolverVR.Spine spine, float weight) { spine.positionWeight = weight; spine.rotationWeight = weight; - if (lookAtIk != null) - lookAtIk.solver.IKPositionWeight = weight; } public static void SetArmWeight(IKSolverVR.Arm arm, float weight) { arm.positionWeight = weight; arm.rotationWeight = weight; - arm.shoulderRotationWeight = weight; - arm.shoulderTwistWeight = weight; + //arm.shoulderRotationWeight = weight; + //arm.shoulderTwistWeight = weight; arm.bendGoalWeight = arm.bendGoal != null ? weight : 0f; } @@ -117,5 +127,21 @@ public class BodyControl spine.pelvisRotationWeight = weight; } + public static void SetLocomotionWeight(IKSolverVR.Locomotion locomotion, float weight) + { + locomotion.weight = weight; + } + + public static void SetIKPositionWeight(IKSolverVR solver, float weight) + { + solver.IKPositionWeight = weight; + } + + public static void SetIKPositionWeight(LookAtIK lookAtIk, float weight) + { + if (lookAtIk != null) + lookAtIk.solver.IKPositionWeight = weight; + } + #endregion } \ No newline at end of file diff --git a/AlternateIKSystem/IK/IKCalibrator.cs b/AlternateIKSystem/IK/IKCalibrator.cs index 545f8af..aff9891 100644 --- a/AlternateIKSystem/IK/IKCalibrator.cs +++ b/AlternateIKSystem/IK/IKCalibrator.cs @@ -1,14 +1,17 @@ using RootMotion.FinalIK; using UnityEngine; +using Object = UnityEngine.Object; namespace NAK.AlternateIKSystem.IK; internal static class IKCalibrator { + #region VRIK Setup + public static VRIK SetupVrIk(Animator animator) { if (animator.gameObject.TryGetComponent(out VRIK vrik)) - UnityEngine.Object.DestroyImmediate(vrik); + Object.DestroyImmediate(vrik); vrik = animator.gameObject.AddComponent(); vrik.AutoDetectReferences(); @@ -66,6 +69,10 @@ internal static class IKCalibrator // hack to prevent death vrik.fixTransforms = !animator.enabled; + // Avatar Motion Tweaker uses this hack! + vrik.solver.leftLeg.useAnimatedBendNormal = false; + vrik.solver.rightLeg.useAnimatedBendNormal = false; + // purposefully initiating early vrik.solver.Initiate(vrik.transform); vrik.solver.Reset(); @@ -106,6 +113,10 @@ internal static class IKCalibrator twistRelaxer.parentChildCrossfade = 0.8f; } + #endregion + + #region VRIK Configuration + public static void ConfigureDesktopVrIk(VRIK vrik) { // From DesktopVRIK @@ -170,6 +181,8 @@ internal static class IKCalibrator vrik.solver.plantFeet = false; } + #endregion + // TODO: figure out proper Desktop & VR organization public static void SetupHeadIKTargetDesktop(VRIK vrik) { diff --git a/AlternateIKSystem/IK/IKHandlers/IKHandler.cs b/AlternateIKSystem/IK/IKHandlers/IKHandler.cs index 92bf802..5e6a40a 100644 --- a/AlternateIKSystem/IK/IKHandlers/IKHandler.cs +++ b/AlternateIKSystem/IK/IKHandlers/IKHandler.cs @@ -5,32 +5,150 @@ using UnityEngine; namespace NAK.AlternateIKSystem.IK.IKHandlers; -internal class IKHandler +internal abstract class IKHandler { + #region Variables + internal VRIK _vrik; internal IKSolverVR _solver; + internal bool shouldTrackAll = true; + internal bool shouldTrackHead = true; + internal bool shouldTrackLeftArm = true; + internal bool shouldTrackRightArm = true; + internal bool shouldTrackLeftLeg = true; + internal bool shouldTrackRightLeg = true; + internal bool shouldTrackPelvis = true; + internal bool shouldTrackLocomotion = true; + + // VRIK Calibration Info + internal VRIKLocomotionData _locomotionData; + // Last Movement Parent Info internal Vector3 _movementPosition; internal Quaternion _movementRotation; internal CVRMovementParent _movementParent; - #region Virtual Methods + // Solver Info + internal float _scaleDifference = 1f; + internal float _locomotionWeight = 1f; + internal float _ikSimulatedRootAngle = 0f; + internal bool _wasTrackingLocomotion = false; - public virtual void OnInitializeIk() + #endregion + + #region Virtual Game Methods + + public virtual void OnInitializeIk() { } + + public virtual void OnPlayerScaled(float scaleDifference) { } + + public virtual void OnPlayerHandleMovementParent(CVRMovementParent currentParent) { } + + #endregion + + #region Virtual IK Weights + + public virtual void UpdateWeights() { + if (!shouldTrackAll) + return; + + if (shouldTrackHead) + Update_HeadWeight(); + + if (shouldTrackLeftArm) + Update_LeftArmWeight(); + + if (shouldTrackRightArm) + Update_RightArmWeight(); + + if (shouldTrackLeftLeg) + Update_LeftLegWeight(); + + if (shouldTrackRightLeg) + Update_RightLegWeight(); + + if (shouldTrackPelvis) + Update_PelvisWeight(); + + if (shouldTrackLocomotion) + { + Update_LocomotionWeight(); + ResetSolverIfNeeded(); + } + + Update_IKPositionWeight(); } - public virtual void OnUpdate() + protected virtual void Update_HeadWeight() { + float targetWeight = GetTargetWeight(BodyControl.TrackingHead, true); + BodyControl.SetHeadWeight(_solver.spine, targetWeight); + BodyControl.SetLookAtWeight(IKManager.lookAtIk, targetWeight); } - public virtual void OnPlayerScaled(float scaleDifference, VRIKCalibrationData calibrationData) + protected virtual void Update_LeftArmWeight() { + float leftArmWeight = GetTargetWeight(BodyControl.TrackingLeftArm, _solver.leftArm.target != null); + BodyControl.SetArmWeight(_solver.leftArm, leftArmWeight); } - public virtual void OnPlayerHandleMovementParent(CVRMovementParent currentParent) + protected virtual void Update_RightArmWeight() { + float rightArmWeight = GetTargetWeight(BodyControl.TrackingRightArm, _solver.rightArm.target != null); + BodyControl.SetArmWeight(_solver.rightArm, rightArmWeight); + } + + protected virtual void Update_LeftLegWeight() + { + float leftLegWeight = GetTargetWeight(BodyControl.TrackingLeftLeg, _solver.leftLeg.target != null); + BodyControl.SetLegWeight(_solver.leftLeg, leftLegWeight); + } + + protected virtual void Update_RightLegWeight() + { + float rightLegWeight = GetTargetWeight(BodyControl.TrackingRightLeg, _solver.rightLeg.target != null); + BodyControl.SetLegWeight(_solver.rightLeg, rightLegWeight); + } + + protected virtual void Update_PelvisWeight() + { + float pelvisWeight = GetTargetWeight(BodyControl.TrackingPelvis, _solver.spine.pelvisTarget != null); + BodyControl.SetPelvisWeight(_solver.spine, pelvisWeight); + } + + protected virtual void Update_LocomotionWeight() + { + _locomotionWeight = Mathf.Lerp(_locomotionWeight, BodyControl.TrackingLocomotion ? 1f : 0f, + Time.deltaTime * ModSettings.EntryIKLerpSpeed.Value * 2f); + BodyControl.SetLocomotionWeight(_solver.locomotion, _locomotionWeight); + } + + protected virtual void Update_IKPositionWeight() + { + float ikPositionWeight = BodyControl.TrackingAll ? BodyControl.TrackingIKPositionWeight : 0f; + BodyControl.SetIKPositionWeight(_solver, ikPositionWeight); + BodyControl.SetIKPositionWeight(IKManager.lookAtIk, ikPositionWeight); + } + + protected virtual float GetTargetWeight(bool isTracking, bool hasTarget) + { + return isTracking && hasTarget ? 1f : 0f; + } + + #endregion + + #region Private Methods + + private void ResetSolverIfNeeded() + { + if (_wasTrackingLocomotion == BodyControl.TrackingLocomotion) + return; + + _wasTrackingLocomotion = BodyControl.TrackingLocomotion; + VRIKUtils.ResetToInitialFootsteps(_vrik, _locomotionData, _scaleDifference); + _solver.Reset(); } #endregion diff --git a/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs b/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs index 96c1e61..46b9e2f 100644 --- a/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs +++ b/AlternateIKSystem/IK/IKHandlers/IKHandlerDesktop.cs @@ -2,7 +2,6 @@ using NAK.AlternateIKSystem.VRIKHelpers; using RootMotion.FinalIK; using UnityEngine; -using UnityEngine.Events; namespace NAK.AlternateIKSystem.IK.IKHandlers; @@ -14,44 +13,44 @@ internal class IKHandlerDesktop : IKHandler _solver = vrik.solver; } - #region Overrides + #region Game Overrides public override void OnInitializeIk() { - _vrik.onPreSolverUpdate.AddListener(new UnityAction(OnPreSolverUpdate)); + // Default tracking for Desktop + shouldTrackHead = true; + shouldTrackLeftArm = false; + shouldTrackRightArm = false; + shouldTrackLeftLeg = false; + shouldTrackRightLeg = false; + shouldTrackPelvis = false; + shouldTrackLocomotion = true; + + _vrik.onPreSolverUpdate.AddListener(OnPreSolverUpdateDesktop); } - public override void OnUpdate() - { - // Reset avatar local position - _vrik.transform.localPosition = Vector3.zero; - _vrik.transform.localRotation = Quaternion.identity; - - UpdateWeights(); - } - - public override void OnPlayerScaled(float scaleDifference, VRIKCalibrationData calibrationData) + public override void OnPlayerScaled(float scaleDifference) { VRIKUtils.ApplyScaleToVRIK ( _vrik, - calibrationData, - scaleDifference + _locomotionData, + _scaleDifference = scaleDifference ); } public override void OnPlayerHandleMovementParent(CVRMovementParent currentParent) { // Get current position - var currentPosition = currentParent._referencePoint.position; - var currentRotation = Quaternion.Euler(0f, currentParent.transform.rotation.eulerAngles.y, 0f); + 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) - var deltaPosition = currentPosition - _movementPosition; - var deltaRotation = Quaternion.Inverse(_movementRotation) * currentRotation; + Vector3 deltaPosition = currentPosition - _movementPosition; + Quaternion deltaRotation = Quaternion.Inverse(_movementRotation) * currentRotation; // Desktop pivots from playerlocal transform - var platformPivot = IKManager.Instance.transform.position; + Vector3 platformPivot = IKManager.Instance.transform.position; // Prevent targeting other parent position if (_movementParent == currentParent) @@ -68,11 +67,76 @@ internal class IKHandlerDesktop : IKHandler #endregion + #region Weight Overrides + + public override void UpdateWeights() + { + // Reset avatar local position + _vrik.transform.localPosition = Vector3.zero; + _vrik.transform.localRotation = Quaternion.identity; + + base.UpdateWeights(); + + // Desktop should never have head position weight + _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 - private float _ikSimulatedRootAngle = 0f; - - private void OnPreSolverUpdate() + private void OnPreSolverUpdateDesktop() { _solver.plantFeet = ModSettings.EntryPlantFeet.Value; @@ -98,7 +162,7 @@ internal class IKHandlerDesktop : IKHandler deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit; _ikSimulatedRootAngle = Mathf.MoveTowardsAngle(_ikSimulatedRootAngle, IKManager.Instance.transform.eulerAngles.y, absDeltaAngleRoot - weightedAngleLimit); } - + _solver.spine.rootHeadingOffset = deltaAngleRoot; if (ModSettings.EntryPelvisHeadingWeight.Value > 0) @@ -115,59 +179,4 @@ internal class IKHandlerDesktop : IKHandler } #endregion - - #region Private Methods - - private float _locomotionWeight = 1f; - - private void UpdateWeights() - { - // Lerp locomotion weight, lerp to BodyControl.TrackingUpright??? - float targetWeight = - (BodyControl.TrackingAll && BodyControl.TrackingLocomotion && BodyControl.AvatarUpright > 0.8f) - ? 1f - : 0.0f; - _locomotionWeight = Mathf.Lerp(_locomotionWeight, targetWeight, Time.deltaTime * 20f); - - if (BodyControl.TrackingAll) - { - _vrik.enabled = true; - _solver.IKPositionWeight = BodyControl.TrackingPositionWeight; - _solver.locomotion.weight = _locomotionWeight; - _solver.spine.maxRootAngle = BodyControl.TrackingMaxRootAngle; - - BodyControl.SetHeadWeight(_solver.spine, IKManager.lookAtIk, BodyControl.TrackingHead ? 1f : 0f); - - BodyControl.SetArmWeight(_solver.leftArm, BodyControl.TrackingLeftArm && _solver.leftArm.target != null ? 1f : 0f); - BodyControl.SetArmWeight(_solver.rightArm, BodyControl.TrackingRightArm && _solver.rightArm.target != null ? 1f : 0f); - - BodyControl.SetLegWeight(_solver.leftLeg, BodyControl.TrackingLeftLeg && _solver.leftLeg.target != null ? 1f : 0f); - BodyControl.SetLegWeight(_solver.rightLeg, BodyControl.TrackingRightLeg && _solver.rightLeg.target != null ? 1f : 0f); - - BodyControl.SetPelvisWeight(_solver.spine, BodyControl.TrackingPelvis && _solver.spine.pelvisTarget != null ? 1f : 0f); - } - else - { - _vrik.enabled = false; - _solver.IKPositionWeight = 0f; - _solver.locomotion.weight = 0f; - _solver.spine.maxRootAngle = 0f; - - BodyControl.SetHeadWeight(_solver.spine, IKManager.lookAtIk, 0f); - BodyControl.SetArmWeight(_solver.leftArm, 0f); - BodyControl.SetArmWeight(_solver.rightArm, 0f); - BodyControl.SetLegWeight(_solver.leftLeg, 0f); - BodyControl.SetLegWeight(_solver.rightLeg, 0f); - BodyControl.SetPelvisWeight(_solver.spine, 0f); - } - - // Desktop should never have head position weight - _solver.spine.positionWeight = 0f; - - // Avatar Motion Tweaker uses this hack, so we must reset it - _solver.leftLeg.useAnimatedBendNormal = false; - _solver.rightLeg.useAnimatedBendNormal = false; - } - - #endregion } \ No newline at end of file diff --git a/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs b/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs new file mode 100644 index 0000000..d94ecdb --- /dev/null +++ b/AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs @@ -0,0 +1,67 @@ +using ABI.CCK.Components; +using NAK.AlternateIKSystem.VRIKHelpers; +using RootMotion.FinalIK; +using UnityEngine; + +namespace NAK.AlternateIKSystem.IK.IKHandlers; + +internal class IKHandlerHalfBody : IKHandler +{ + public IKHandlerHalfBody(VRIK vrik) + { + _vrik = vrik; + _solver = vrik.solver; + } + + #region Game Overrides + + public override void OnInitializeIk() + { + // Default tracking for HalfBody + shouldTrackHead = true; + shouldTrackLeftArm = true; + shouldTrackRightArm = true; + shouldTrackLeftLeg = false; + shouldTrackRightLeg = false; + shouldTrackPelvis = false; + shouldTrackLocomotion = true; + } + + 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 +} \ No newline at end of file diff --git a/AlternateIKSystem/IK/IKManager.cs b/AlternateIKSystem/IK/IKManager.cs index 1956ea9..0a8b15e 100644 --- a/AlternateIKSystem/IK/IKManager.cs +++ b/AlternateIKSystem/IK/IKManager.cs @@ -1,7 +1,6 @@ using ABI.CCK.Components; using ABI_RC.Core.Player; using ABI_RC.Core.Savior; -using ABI_RC.Systems.MovementSystem; using NAK.AlternateIKSystem.IK.IKHandlers; using NAK.AlternateIKSystem.VRIKHelpers; using RootMotion.FinalIK; @@ -14,6 +13,8 @@ public class IKManager : MonoBehaviour { public static IKManager Instance; + #region Variables + public BodyControl BodyControl = new BodyControl(); public static VRIK vrik => _vrik; @@ -44,8 +45,9 @@ public class IKManager : MonoBehaviour private HumanPose _humanPose; private HumanPose _humanPoseInitial; - // VRIK Calibration Info - private VRIKCalibrationData _calibrationData; + #endregion + + #region Unity Methods private void Start() { @@ -67,9 +69,11 @@ public class IKManager : MonoBehaviour if (!_isAvatarInitialized) return; - _ikHandler?.OnUpdate(); + _ikHandler?.UpdateWeights(); } + #endregion + #region Avatar Events public void OnAvatarInitialized(GameObject inAvatar) @@ -137,7 +141,7 @@ public class IKManager : MonoBehaviour if (!_isAvatarInitialized) return false; - _ikHandler?.OnPlayerScaled(scaleDifference, _calibrationData); + _ikHandler?.OnPlayerScaled(scaleDifference); return true; } @@ -164,7 +168,7 @@ public class IKManager : MonoBehaviour { if (!_isAvatarInitialized) return false; - + _vrik?.solver.Reset(); return true; } @@ -175,23 +179,31 @@ public class IKManager : MonoBehaviour private void InitializeDesktopIk() { - PreSetupIkGeneral(); + SetupIkGeneral(); + IKCalibrator.ConfigureDesktopVrIk(_vrik); + _ikHandler = new IKHandlerDesktop(_vrik); + IKCalibrator.SetupHeadIKTargetDesktop(_vrik); + InitializeIkGeneral(); - _ikHandler = new IKHandlerDesktop(_vrik); _ikHandler.OnInitializeIk(); } private void InitializeHalfBodyIk() { - PreSetupIkGeneral(); + SetupIkGeneral(); + IKCalibrator.ConfigureHalfBodyVrIk(_vrik); + _ikHandler = new IKHandlerHalfBody(_vrik); + InitializeIkGeneral(); + + _ikHandler.OnInitializeIk(); } - private void PreSetupIkGeneral() + private void SetupIkGeneral() { SetAvatarPose(AvatarPose.Default); _vrik = IKCalibrator.SetupVrIk(_animator); @@ -201,12 +213,12 @@ public class IKManager : MonoBehaviour { SetAvatarPose(AvatarPose.IKPose); - VRIKUtils.CalculateInitialIKScaling(_vrik, ref _calibrationData); - VRIKUtils.CalculateInitialFootsteps(_vrik, ref _calibrationData); + VRIKUtils.CalculateInitialIKScaling(_vrik, ref _ikHandler._locomotionData); + VRIKUtils.CalculateInitialFootsteps(_vrik, ref _ikHandler._locomotionData); - VRIKUtils.ApplyScaleToVRIK(_vrik, _calibrationData, 1f); + _vrik.solver.Initiate(_vrik.transform); // initiate a second time - VRIKUtils.InitiateVRIKSolver(_vrik); // initiate again to store ikpose + VRIKUtils.ApplyScaleToVRIK(_vrik, _ikHandler._locomotionData, 1f); _vrik.onPreSolverUpdate.AddListener(new UnityAction(OnPreSolverUpdateGeneral)); _vrik.onPostSolverUpdate.AddListener(new UnityAction(OnPostSolverUpdateGeneral)); @@ -263,6 +275,7 @@ public class IKManager : MonoBehaviour _hipTransform.rotation = hipRot; } + // "NetIk Pass", or "Additional Humanoid Pass" hack private void OnPostSolverUpdateGeneral() { Vector3 hipPos = _hipTransform.position; diff --git a/AlternateIKSystem/IK/VRIKHelpers/VRIKCalibrationData.cs b/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs similarity index 72% rename from AlternateIKSystem/IK/VRIKHelpers/VRIKCalibrationData.cs rename to AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs index c49e4b3..a647071 100644 --- a/AlternateIKSystem/IK/VRIKHelpers/VRIKCalibrationData.cs +++ b/AlternateIKSystem/IK/VRIKHelpers/VRIKLocomotionData.cs @@ -2,28 +2,22 @@ namespace NAK.AlternateIKSystem.VRIKHelpers; -public struct VRIKCalibrationData +public struct VRIKLocomotionData { - public Vector3 KneeNormalLeft; - public Vector3 KneeNormalRight; public Vector3 InitialFootPosLeft; public Vector3 InitialFootPosRight; public Quaternion InitialFootRotLeft; public Quaternion InitialFootRotRight; - public float InitialHeadHeight; public float InitialFootDistance; public float InitialStepThreshold; public float InitialStepHeight; public void Clear() { - KneeNormalLeft = Vector3.zero; - KneeNormalRight = Vector3.zero; InitialFootPosLeft = Vector3.zero; InitialFootPosRight = Vector3.zero; InitialFootRotLeft = Quaternion.identity; InitialFootRotRight = Quaternion.identity; - InitialHeadHeight = 0f; InitialFootDistance = 0f; InitialStepThreshold = 0f; InitialStepHeight = 0f; diff --git a/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs b/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs index 2f06a32..4c2ba81 100644 --- a/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs +++ b/AlternateIKSystem/IK/VRIKHelpers/VRIKUtils.cs @@ -5,72 +5,18 @@ namespace NAK.AlternateIKSystem.VRIKHelpers; public static class VRIKUtils { - public static void CalculateKneeBendNormals(VRIK vrik, ref VRIKCalibrationData calibrationData) - { - // Helper function to get position or default to Vector3.zero - Vector3 GetPositionOrDefault(Transform transform) => transform?.position ?? Vector3.zero; - - // Get assumed left knee normal - Vector3[] leftVectors = { - GetPositionOrDefault(vrik.references.leftThigh), - GetPositionOrDefault(vrik.references.leftCalf), - GetPositionOrDefault(vrik.references.leftFoot) - }; - calibrationData.KneeNormalLeft = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(leftVectors); - - // Get assumed right knee normal - Vector3[] rightVectors = { - GetPositionOrDefault(vrik.references.rightThigh), - GetPositionOrDefault(vrik.references.rightCalf), - GetPositionOrDefault(vrik.references.rightFoot) - }; - calibrationData.KneeNormalRight = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(rightVectors); - } - - public static void ApplyKneeBendNormals(VRIK vrik, VRIKCalibrationData calibrationData) - { - // 0 uses bendNormalRelToPelvis, 1 is bendNormalRelToTarget - // modifying pelvis normal weight is easier math - vrik.solver.leftLeg.bendToTargetWeight = 0f; - vrik.solver.rightLeg.bendToTargetWeight = 0f; - - var pelvis_localRotationInverse = Quaternion.Inverse(vrik.references.pelvis.localRotation); - vrik.solver.leftLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * calibrationData.KneeNormalLeft; - vrik.solver.rightLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * calibrationData.KneeNormalRight; - } - - private static Vector3 GetNormalFromArray(Vector3[] positions) - { - Vector3 centroid = Vector3.zero; - for (int i = 0; i < positions.Length; i++) - { - centroid += positions[i]; - } - centroid /= positions.Length; - - Vector3 normal = Vector3.zero; - for (int i = 0; i < positions.Length - 2; i++) - { - Vector3 side1 = positions[i] - centroid; - Vector3 side2 = positions[i + 1] - centroid; - normal += Vector3.Cross(side1, side2); - } - return normal.normalized; - } - - public static void CalculateInitialIKScaling(VRIK vrik, ref VRIKCalibrationData calibrationData) + public static void CalculateInitialIKScaling(VRIK vrik, ref VRIKLocomotionData locomotionData) { // Get distance between feet and thighs float scaleModifier = Mathf.Max(1f, vrik.references.pelvis.lossyScale.x); float footDistance = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.rightFoot.position); - calibrationData.InitialFootDistance = footDistance * 0.5f; - calibrationData.InitialStepThreshold = footDistance * scaleModifier; - calibrationData.InitialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f; - calibrationData.InitialHeadHeight = Mathf.Abs(vrik.references.head.position.y - vrik.references.rightFoot.position.y); + locomotionData.InitialFootDistance = footDistance * 0.5f; + locomotionData.InitialStepThreshold = footDistance * scaleModifier; + locomotionData.InitialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f; } - public static void CalculateInitialFootsteps(VRIK vrik, ref VRIKCalibrationData calibrationData) + public static void CalculateInitialFootsteps(VRIK vrik, ref VRIKLocomotionData locomotionData) { Transform root = vrik.references.root; Transform leftFoot = vrik.references.leftFoot; @@ -80,46 +26,37 @@ public static class VRIKUtils Quaternion rootWorldRot = root.rotation; // Calculate the world rotation of the left and right feet relative to the root bone - calibrationData.InitialFootPosLeft = root.parent.InverseTransformPoint(leftFoot.position); - calibrationData.InitialFootPosRight = root.parent.InverseTransformPoint(rightFoot.position); - calibrationData.InitialFootRotLeft = Quaternion.Inverse(rootWorldRot) * leftFoot.rotation; - calibrationData.InitialFootRotRight = Quaternion.Inverse(rootWorldRot) * rightFoot.rotation; + locomotionData.InitialFootPosLeft = root.InverseTransformPoint(leftFoot.position); + locomotionData.InitialFootPosRight = root.InverseTransformPoint(rightFoot.position); + locomotionData.InitialFootRotLeft = Quaternion.Inverse(rootWorldRot) * leftFoot.rotation; + locomotionData.InitialFootRotRight = Quaternion.Inverse(rootWorldRot) * rightFoot.rotation; } - public static void ResetToInitialFootsteps(VRIK vrik, VRIKCalibrationData calibrationData, float scaleModifier) + public static void ResetToInitialFootsteps(VRIK vrik, VRIKLocomotionData locomotionData, float scaleModifier) { - var locomotionSolver = vrik.solver.locomotion; + Transform root = vrik.references.root; + Quaternion rootWorldRot = vrik.references.root.rotation; - var footsteps = locomotionSolver.footsteps; - var footstepLeft = footsteps[0]; - var footstepRight = footsteps[1]; - - var root = vrik.references.root; - var rootWorldRot = vrik.references.root.rotation; - - // hack, use parent transform instead as setting feet position moves root - footstepLeft.Reset(rootWorldRot, root.parent.TransformPoint(calibrationData.InitialFootPosLeft * scaleModifier), rootWorldRot * calibrationData.InitialFootRotLeft); - footstepRight.Reset(rootWorldRot, root.parent.TransformPoint(calibrationData.InitialFootPosRight * scaleModifier), rootWorldRot * calibrationData.InitialFootRotRight); + // hack, use parent transform instead as setting feet position moves root (root.parent), but does not work for VR + var footsteps = vrik.solver.locomotion.footsteps; + footsteps[0].Reset(rootWorldRot, root.TransformPoint(locomotionData.InitialFootPosLeft * scaleModifier), + rootWorldRot * locomotionData.InitialFootRotLeft); + footsteps[1].Reset(rootWorldRot, root.TransformPoint(locomotionData.InitialFootPosRight * scaleModifier), + rootWorldRot * locomotionData.InitialFootRotRight); } - public static void ApplyScaleToVRIK(VRIK vrik, VRIKCalibrationData calibrationData, float scaleModifier) + public static void ApplyScaleToVRIK(VRIK vrik, VRIKLocomotionData locomotionData, float scaleModifier) { - var locomotionSolver = vrik.solver.locomotion; - locomotionSolver.footDistance = calibrationData.InitialFootDistance * scaleModifier; - locomotionSolver.stepThreshold = calibrationData.InitialStepThreshold * scaleModifier; - ScaleStepHeight(locomotionSolver.stepHeight, calibrationData.InitialStepHeight * scaleModifier); + IKSolverVR.Locomotion locomotionSolver = vrik.solver.locomotion; + locomotionSolver.footDistance = locomotionData.InitialFootDistance * scaleModifier; + locomotionSolver.stepThreshold = locomotionData.InitialStepThreshold * scaleModifier; + ScaleStepHeight(locomotionSolver.stepHeight, locomotionData.InitialStepHeight * scaleModifier); } - static void ScaleStepHeight(AnimationCurve stepHeightCurve, float mag) + private static void ScaleStepHeight(AnimationCurve stepHeightCurve, float mag) { - Keyframe[] keyframes = stepHeightCurve.keys; + var keyframes = stepHeightCurve.keys; keyframes[1].value = mag; stepHeightCurve.keys = keyframes; } - - public static void InitiateVRIKSolver(VRIK vrik) - { - vrik.solver.SetToReferences(vrik.references); - vrik.solver.Initiate(vrik.transform); - } } \ No newline at end of file diff --git a/AlternateIKSystem/Integrations/BTKUIAddon.cs b/AlternateIKSystem/Integrations/BTKUIAddon.cs index 2c03496..fb51329 100644 --- a/AlternateIKSystem/Integrations/BTKUIAddon.cs +++ b/AlternateIKSystem/Integrations/BTKUIAddon.cs @@ -25,7 +25,7 @@ public static class BTKUIAddon Page generalIKPage = parentCategory.AddPage("General IK Settings", "", "Configure the settings for general IK.", ModSettings.SettingsCategory); generalIKPage.MenuTitle = "General IK Settings"; Category generalIKCategory = generalIKPage.AddCategory(generalIKPage.MenuTitle); - + // General Settings AddMelonToggle(ref generalIKCategory, ModSettings.EntryPlantFeet); diff --git a/AlternateIKSystem/Main.cs b/AlternateIKSystem/Main.cs index d82f2cf..37fa7ea 100644 --- a/AlternateIKSystem/Main.cs +++ b/AlternateIKSystem/Main.cs @@ -26,7 +26,7 @@ public class AlternateIKSystem : MelonMod private static void InitializeIntegration(string modName, Action integrationAction) { - if (RegisteredMelons.All(it => it.Info.Name != modName)) + if (RegisteredMelons.All(it => it.Info.Name != modName)) return; Logger.Msg($"Initializing {modName} integration.");