mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-02 14:29:25 +00:00
[AlternateIKSystem] Slight cleanup
This commit is contained in:
parent
684b330a4c
commit
cd34aebeb0
10 changed files with 380 additions and 203 deletions
|
@ -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
|
||||
}
|
|
@ -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>();
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
67
AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs
Normal file
67
AlternateIKSystem/IK/IKHandlers/IKHandlerHalfBody.cs
Normal file
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue