diff --git a/DesktopVRIK/DesktopVRIK.csproj b/DesktopVRIK/DesktopVRIK.csproj
index 66a50a8..e94f9dc 100644
--- a/DesktopVRIK/DesktopVRIK.csproj
+++ b/DesktopVRIK/DesktopVRIK.csproj
@@ -1,2 +1,2 @@
-
+
diff --git a/DesktopVRIK/DesktopVRIKCalibrator.cs b/DesktopVRIK/DesktopVRIKCalibrator.cs
new file mode 100644
index 0000000..66da1ab
--- /dev/null
+++ b/DesktopVRIK/DesktopVRIKCalibrator.cs
@@ -0,0 +1,321 @@
+using ABI_RC.Core.Base;
+using ABI_RC.Systems.IK;
+using ABI_RC.Systems.IK.SubSystems;
+using NAK.DesktopVRIK.VRIKHelper;
+using RootMotion.FinalIK;
+using UnityEngine;
+using UnityEngine.Events;
+
+namespace NAK.DesktopVRIK;
+
+internal class DesktopVRIKCalibrator
+{
+ public static Dictionary BoneExists;
+ public static readonly float[] IKPoseMuscles = new float[]
+ {
+ 0.00133321f,
+ 8.195831E-06f,
+ 8.537738E-07f,
+ -0.002669832f,
+ -7.651234E-06f,
+ -0.001659694f,
+ 0f,
+ 0f,
+ 0f,
+ 0.04213953f,
+ 0.0003007996f,
+ -0.008032114f,
+ -0.03059979f,
+ -0.0003182998f,
+ 0.009640567f,
+ 0f,
+ 0f,
+ 0f,
+ 0f,
+ 0f,
+ 0f,
+ 0.5768794f,
+ 0.01061097f,
+ -0.1127839f,
+ 0.9705755f,
+ 0.07972051f,
+ -0.0268422f,
+ 0.007237188f,
+ 0f,
+ 0.5768792f,
+ 0.01056608f,
+ -0.1127519f,
+ 0.9705756f,
+ 0.07971933f,
+ -0.02682396f,
+ 0.007229362f,
+ 0f,
+ -5.651802E-06f,
+ -3.034899E-07f,
+ 0.4100508f,
+ 0.3610304f,
+ -0.0838329f,
+ 0.9262537f,
+ 0.1353517f,
+ -0.03578902f,
+ 0.06005657f,
+ -4.95989E-06f,
+ -1.43007E-06f,
+ 0.4096187f,
+ 0.363263f,
+ -0.08205152f,
+ 0.9250782f,
+ 0.1345718f,
+ -0.03572125f,
+ 0.06055461f,
+ -1.079177f,
+ 0.2095419f,
+ 0.6140652f,
+ 0.6365265f,
+ 0.6683931f,
+ -0.4764312f,
+ 0.8099416f,
+ 0.8099371f,
+ 0.6658203f,
+ -0.7327053f,
+ 0.8113618f,
+ 0.8114051f,
+ 0.6643661f,
+ -0.40341f,
+ 0.8111364f,
+ 0.8111367f,
+ 0.6170399f,
+ -0.2524227f,
+ 0.8138723f,
+ 0.8110135f,
+ -1.079171f,
+ 0.2095456f,
+ 0.6140658f,
+ 0.6365255f,
+ 0.6683878f,
+ -0.4764301f,
+ 0.8099402f,
+ 0.8099376f,
+ 0.6658241f,
+ -0.7327023f,
+ 0.8113653f,
+ 0.8113793f,
+ 0.664364f,
+ -0.4034042f,
+ 0.811136f,
+ 0.8111364f,
+ 0.6170469f,
+ -0.2524345f,
+ 0.8138595f,
+ 0.8110138f
+ };
+ enum AvatarPose
+ {
+ Default = 0,
+ Initial = 1,
+ IKPose = 2,
+ TPose = 3
+ }
+
+ readonly DesktopVRIKSystem ikSystem;
+
+ // Avatar Components
+ Animator _animator;
+
+ // Calibration Objects
+ public HumanPoseHandler _humanPoseHandler;
+ public HumanPose _humanPose;
+ public HumanPose _humanPoseInitial;
+
+ // Animator Info
+ int _animLocomotionLayer = -1;
+ int _animIKPoseLayer = -1;
+
+ internal DesktopVRIKCalibrator()
+ {
+ ikSystem = DesktopVRIKSystem.Instance;
+ BoneExists = new Dictionary();
+ }
+
+ public void ApplyNetIKPass()
+ {
+ Transform hipTransform = _animator.GetBoneTransform(HumanBodyBones.Hips);
+ Vector3 hipPosition = hipTransform.position;
+ Quaternion hipRotation = hipTransform.rotation;
+
+ _humanPoseHandler.GetHumanPose(ref _humanPose);
+ _humanPoseHandler.SetHumanPose(ref _humanPose);
+
+ hipTransform.position = hipPosition;
+ hipTransform.rotation = hipRotation;
+ }
+
+ public void CalibrateDesktopVRIK(Animator animator)
+ {
+ ScanAvatar(animator);
+ SetupVRIK();
+ CalibrateVRIK();
+ ConfigureVRIK();
+ }
+
+ void ScanAvatar(Animator animator)
+ {
+ // Find required avatar components
+ _animator = animator;
+ ikSystem.avatarTransform = animator.gameObject.transform;
+ ikSystem.avatarLookAtIK = animator.gameObject.GetComponent();
+
+ // Get animator layer inticies
+ _animIKPoseLayer = _animator.GetLayerIndex("IKPose");
+ _animLocomotionLayer = _animator.GetLayerIndex("Locomotion/Emotes");
+
+ // Dispose and create new _humanPoseHandler
+ _humanPoseHandler?.Dispose();
+ _humanPoseHandler = new HumanPoseHandler(_animator.avatar, ikSystem.avatarTransform);
+
+ // Get initial human poses
+ _humanPoseHandler.GetHumanPose(ref _humanPose);
+ _humanPoseHandler.GetHumanPose(ref _humanPoseInitial);
+
+ ikSystem.calibrationData.Clear();
+
+ // Dumb fix for rare upload issue
+ ikSystem.calibrationData.FixTransformsRequired = !_animator.enabled;
+
+ // Find available HumanoidBodyBones
+ BoneExists.Clear();
+ foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones)))
+ {
+ if (bone != HumanBodyBones.LastBone)
+ {
+ BoneExists.Add(bone, _animator.GetBoneTransform(bone) != null);
+ }
+ }
+ }
+
+ void SetupVRIK()
+ {
+ // Add and configure VRIK
+ ikSystem.avatarVRIK = ikSystem.avatarTransform.AddComponentIfMissing();
+ ikSystem.avatarVRIK.AutoDetectReferences();
+ ikSystem.cachedSolver = new CachedSolver(ikSystem.avatarVRIK.solver);
+
+ // Why do I love to overcomplicate things?
+ VRIKUtils.ConfigureVRIKReferences(ikSystem.avatarVRIK, DesktopVRIK.EntryUseVRIKToes.Value);
+ VRIKConfigurator.ApplyVRIKConfiguration(ikSystem.cachedSolver, VRIKConfigurations.DesktopVRIKConfiguration());
+
+ // Fix potential animator issue
+ ikSystem.avatarVRIK.fixTransforms = ikSystem.calibrationData.FixTransformsRequired;
+ }
+
+ void CalibrateVRIK()
+ {
+ SetAvatarPose(AvatarPose.Default);
+
+ // Calculate bend normals with motorcycle pose
+ VRIKUtils.CalculateKneeBendNormals(ikSystem.avatarVRIK, ref ikSystem.calibrationData);
+
+ SetAvatarPose(AvatarPose.IKPose);
+
+ // Calculate initial IK scaling values with IKPose
+ VRIKUtils.CalculateInitialIKScaling(ikSystem.avatarVRIK, ref ikSystem.calibrationData);
+
+ // Calculate initial Footstep positions
+ VRIKUtils.CalculateInitialFootsteps(ikSystem.avatarVRIK, ref ikSystem.calibrationData);
+
+ // Setup HeadIKTarget
+ VRIKUtils.SetupHeadIKTarget(ikSystem.avatarVRIK);
+
+ // Initiate VRIK manually
+ VRIKUtils.InitiateVRIKSolver(ikSystem.avatarVRIK);
+
+ SetAvatarPose(AvatarPose.Initial);
+ }
+
+ void ConfigureVRIK()
+ {
+ ikSystem.OnSetupIKScaling(1f);
+
+ VRIKUtils.ApplyKneeBendNormals(ikSystem.avatarVRIK, ikSystem.calibrationData);
+
+ ikSystem.avatarVRIK.onPreSolverUpdate.AddListener(new UnityAction(ikSystem.OnPreSolverUpdate));
+ ikSystem.avatarVRIK.onPostSolverUpdate.AddListener(new UnityAction(ikSystem.OnPostSolverUpdate));
+ }
+
+ void SetAvatarPose(AvatarPose pose)
+ {
+ switch (pose)
+ {
+ case AvatarPose.Default:
+ SetMusclesToValue(0f);
+ break;
+ case AvatarPose.Initial:
+ if (HasCustomIKPose())
+ {
+ SetCustomLayersWeights(0f, 1f);
+ return;
+ }
+ _humanPoseHandler.SetHumanPose(ref _humanPoseInitial);
+ break;
+ case AvatarPose.IKPose:
+ if (HasCustomIKPose())
+ {
+ SetCustomLayersWeights(1f, 0f);
+ return;
+ }
+ SetMusclesToPose(IKPoseMuscles);
+ break;
+ case AvatarPose.TPose:
+ SetMusclesToPose(BodySystem.TPoseMuscles);
+ break;
+ default:
+ break;
+ }
+ }
+
+ bool HasCustomIKPose()
+ {
+ return _animLocomotionLayer != -1 && _animIKPoseLayer != -1;
+ }
+
+ void SetCustomLayersWeights(float customIKPoseLayerWeight, float locomotionLayerWeight)
+ {
+ _animator.SetLayerWeight(_animIKPoseLayer, customIKPoseLayerWeight);
+ _animator.SetLayerWeight(_animLocomotionLayer, locomotionLayerWeight);
+ _animator.Update(0f);
+ }
+
+ void SetMusclesToValue(float value)
+ {
+ _humanPoseHandler.GetHumanPose(ref _humanPose);
+
+ for (int i = 0; i < _humanPose.muscles.Length; i++)
+ {
+ ApplyMuscleValue((MuscleIndex)i, value, ref _humanPose.muscles);
+ }
+
+ _humanPose.bodyRotation = Quaternion.identity;
+ _humanPoseHandler.SetHumanPose(ref _humanPose);
+ }
+
+ void SetMusclesToPose(float[] muscles)
+ {
+ _humanPoseHandler.GetHumanPose(ref _humanPose);
+
+ for (int i = 0; i < _humanPose.muscles.Length; i++)
+ {
+ ApplyMuscleValue((MuscleIndex)i, muscles[i], ref _humanPose.muscles);
+ }
+
+ _humanPose.bodyRotation = Quaternion.identity;
+ _humanPoseHandler.SetHumanPose(ref _humanPose);
+ }
+
+ void ApplyMuscleValue(MuscleIndex index, float value, ref float[] muscles)
+ {
+ if (BoneExists.ContainsKey(IKSystem.MusclesToHumanBodyBones[(int)index]) && BoneExists[IKSystem.MusclesToHumanBodyBones[(int)index]])
+ {
+ muscles[(int)index] = value;
+ }
+ }
+}
diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs
index 5d74e70..9883ffd 100644
--- a/DesktopVRIK/DesktopVRIKSystem.cs
+++ b/DesktopVRIK/DesktopVRIKSystem.cs
@@ -1,178 +1,31 @@
using ABI.CCK.Components;
-using ABI_RC.Core.Base;
using ABI_RC.Core.Player;
-using ABI_RC.Systems.IK;
using ABI_RC.Systems.IK.SubSystems;
using ABI_RC.Systems.MovementSystem;
+using NAK.DesktopVRIK.VRIKHelper;
using RootMotion.FinalIK;
using UnityEngine;
-using UnityEngine.Events;
namespace NAK.DesktopVRIK;
internal class DesktopVRIKSystem : MonoBehaviour
{
public static DesktopVRIKSystem Instance;
- public static Dictionary BoneExists;
- public static readonly float[] IKPoseMuscles = new float[]
- {
- 0.00133321f,
- 8.195831E-06f,
- 8.537738E-07f,
- -0.002669832f,
- -7.651234E-06f,
- -0.001659694f,
- 0f,
- 0f,
- 0f,
- 0.04213953f,
- 0.0003007996f,
- -0.008032114f,
- -0.03059979f,
- -0.0003182998f,
- 0.009640567f,
- 0f,
- 0f,
- 0f,
- 0f,
- 0f,
- 0f,
- 0.5768794f,
- 0.01061097f,
- -0.1127839f,
- 0.9705755f,
- 0.07972051f,
- -0.0268422f,
- 0.007237188f,
- 0f,
- 0.5768792f,
- 0.01056608f,
- -0.1127519f,
- 0.9705756f,
- 0.07971933f,
- -0.02682396f,
- 0.007229362f,
- 0f,
- -5.651802E-06f,
- -3.034899E-07f,
- 0.4100508f,
- 0.3610304f,
- -0.0838329f,
- 0.9262537f,
- 0.1353517f,
- -0.03578902f,
- 0.06005657f,
- -4.95989E-06f,
- -1.43007E-06f,
- 0.4096187f,
- 0.363263f,
- -0.08205152f,
- 0.9250782f,
- 0.1345718f,
- -0.03572125f,
- 0.06055461f,
- -1.079177f,
- 0.2095419f,
- 0.6140652f,
- 0.6365265f,
- 0.6683931f,
- -0.4764312f,
- 0.8099416f,
- 0.8099371f,
- 0.6658203f,
- -0.7327053f,
- 0.8113618f,
- 0.8114051f,
- 0.6643661f,
- -0.40341f,
- 0.8111364f,
- 0.8111367f,
- 0.6170399f,
- -0.2524227f,
- 0.8138723f,
- 0.8110135f,
- -1.079171f,
- 0.2095456f,
- 0.6140658f,
- 0.6365255f,
- 0.6683878f,
- -0.4764301f,
- 0.8099402f,
- 0.8099376f,
- 0.6658241f,
- -0.7327023f,
- 0.8113653f,
- 0.8113793f,
- 0.664364f,
- -0.4034042f,
- 0.811136f,
- 0.8111364f,
- 0.6170469f,
- -0.2524345f,
- 0.8138595f,
- 0.8110138f
- };
+ public static DesktopVRIKCalibrator Calibrator;
- enum AvatarPose
- {
- Default = 0,
- Initial = 1,
- IKPose = 2,
- TPose = 3
- }
-
- // DesktopVRIK Settings
- public bool Setting_Enabled = true;
- public bool Setting_PlantFeet;
- public bool Setting_ResetFootsteps;
- public bool Setting_ProneThrusting;
- public float Setting_BodyLeanWeight;
- public float Setting_BodyHeadingLimit;
- public float Setting_PelvisHeadingWeight;
- public float Setting_ChestHeadingWeight;
- public float Setting_IKLerpSpeed;
-
- // Calibration Settings
- public bool Setting_UseVRIKToes;
- public bool Setting_FindUnmappedToes;
-
- // Integration Settings
- public bool Setting_IntegrationAMT;
+ // VRIK Calibration Info
+ public VRIKCalibrationData calibrationData;
// Avatar Components
- public CVRAvatar avatarDescriptor = null;
- public Animator avatarAnimator = null;
- public Transform avatarTransform = null;
- public LookAtIK avatarLookAtIK = null;
public VRIK avatarVRIK = null;
- public IKSolverVR avatarIKSolver = null;
+ public LookAtIK avatarLookAtIK = null;
+ public Transform avatarTransform = null;
+ public CachedSolver cachedSolver;
// ChilloutVR Player Components
PlayerSetup playerSetup;
MovementSystem movementSystem;
- // Calibration Objects
- HumanPose _humanPose;
- HumanPose _humanPoseInitial;
- HumanPoseHandler _humanPoseHandler;
-
- // Animator Info
- int _animLocomotionLayer = -1;
- int _animIKPoseLayer = -1;
-
- // VRIK Calibration Info
- Vector3 _vrikKneeNormalLeft;
- Vector3 _vrikKneeNormalRight;
- Vector3 _vrikInitialFootPosLeft;
- Vector3 _vrikInitialFootPosRight;
- Quaternion _vrikInitialFootRotLeft;
- Quaternion _vrikInitialFootRotRight;
- float _vrikInitialHeadHeight;
- float _vrikInitialFootDistance;
- float _vrikInitialStepThreshold;
- float _vrikInitialStepHeight;
- bool _vrikFixTransformsRequired;
-
// Player Info
Transform _cameraTransform;
bool _ikEmotePlaying;
@@ -186,21 +39,16 @@ internal class DesktopVRIKSystem : MonoBehaviour
Quaternion _movementRotation;
CVRMovementParent _movementParent;
- DesktopVRIKSystem()
- {
- BoneExists = new Dictionary();
- }
-
void Start()
{
Instance = this;
+ Calibrator = new DesktopVRIKCalibrator();
+
playerSetup = GetComponent();
movementSystem = GetComponent();
_cameraTransform = playerSetup.desktopCamera.transform;
-
- DesktopVRIK.UpdateAllSettings();
}
void Update()
@@ -220,7 +68,7 @@ internal class DesktopVRIKSystem : MonoBehaviour
if (shouldTrackLocomotion != BodySystem.TrackingLocomotionEnabled)
{
BodySystem.TrackingLocomotionEnabled = shouldTrackLocomotion;
- avatarIKSolver.Reset();
+ IKResetSolver();
ResetDesktopVRIK();
if (shouldTrackLocomotion) IKResetFootsteps();
}
@@ -242,29 +90,26 @@ internal class DesktopVRIKSystem : MonoBehaviour
bool IsStanding()
{
// Let AMT handle it if available
- if (Setting_IntegrationAMT) return true;
+ if (DesktopVRIK.EntryIntegrationAMT.Value) return true;
// Get Upright value
- Vector3 delta = avatarIKSolver.spine.headPosition - avatarTransform.position;
+ Vector3 delta = cachedSolver.Spine.headPosition - avatarTransform.position;
Vector3 deltaRotated = Quaternion.Euler(0, avatarTransform.rotation.eulerAngles.y, 0) * delta;
- float upright = Mathf.InverseLerp(0f, _vrikInitialHeadHeight * _scaleDifference, deltaRotated.y);
+ float upright = Mathf.InverseLerp(0f, calibrationData.InitialHeadHeight * _scaleDifference, deltaRotated.y);
return upright > 0.85f;
}
-
void UpdateLocomotionWeight()
{
float targetWeight = BodySystem.TrackingEnabled && BodySystem.TrackingLocomotionEnabled ? 1.0f : 0.0f;
- if (Setting_IKLerpSpeed > 0)
+ if (DesktopVRIK.EntryIKLerpSpeed.Value > 0)
{
- _ikWeightLerp = Mathf.Lerp(_ikWeightLerp, targetWeight, Time.deltaTime * Setting_IKLerpSpeed);
- _locomotionWeight = Mathf.Lerp(_locomotionWeight, targetWeight, Time.deltaTime * Setting_IKLerpSpeed * 2f);
- }
- else
- {
- _ikWeightLerp = targetWeight;
- _locomotionWeight = targetWeight;
+ _ikWeightLerp = Mathf.Lerp(_ikWeightLerp, targetWeight, Time.deltaTime * DesktopVRIK.EntryIKLerpSpeed.Value);
+ _locomotionWeight = Mathf.Lerp(_locomotionWeight, targetWeight, Time.deltaTime * DesktopVRIK.EntryIKLerpSpeed.Value * 2f);
+ return;
}
+ _ikWeightLerp = targetWeight;
+ _locomotionWeight = targetWeight;
}
void ApplyBodySystemWeights()
@@ -281,32 +126,33 @@ internal class DesktopVRIKSystem : MonoBehaviour
leg.positionWeight = isTracked ? 1f : 0f;
leg.rotationWeight = isTracked ? 1f : 0f;
}
+
if (BodySystem.TrackingEnabled)
{
avatarVRIK.enabled = true;
- avatarIKSolver.IKPositionWeight = BodySystem.TrackingPositionWeight;
- avatarIKSolver.locomotion.weight = _locomotionWeight;
+ cachedSolver.Solver.IKPositionWeight = BodySystem.TrackingPositionWeight;
+ cachedSolver.Locomotion.weight = _locomotionWeight;
bool useAnimatedBendNormal = _locomotionWeight <= 0.5f;
- avatarIKSolver.leftLeg.useAnimatedBendNormal = useAnimatedBendNormal;
- avatarIKSolver.rightLeg.useAnimatedBendNormal = useAnimatedBendNormal;
- SetArmWeight(avatarIKSolver.leftArm, BodySystem.TrackingLeftArmEnabled && avatarIKSolver.leftArm.target != null);
- SetArmWeight(avatarIKSolver.rightArm, BodySystem.TrackingRightArmEnabled && avatarIKSolver.rightArm.target != null);
- SetLegWeight(avatarIKSolver.leftLeg, BodySystem.TrackingLeftLegEnabled && avatarIKSolver.leftLeg.target != null);
- SetLegWeight(avatarIKSolver.rightLeg, BodySystem.TrackingRightLegEnabled && avatarIKSolver.rightLeg.target != null);
+ cachedSolver.LeftLeg.useAnimatedBendNormal = useAnimatedBendNormal;
+ cachedSolver.RightLeg.useAnimatedBendNormal = useAnimatedBendNormal;
+ SetArmWeight(cachedSolver.LeftArm, BodySystem.TrackingLeftArmEnabled && cachedSolver.LeftArm.target != null);
+ SetArmWeight(cachedSolver.RightArm, BodySystem.TrackingRightArmEnabled && cachedSolver.RightArm.target != null);
+ SetLegWeight(cachedSolver.LeftLeg, BodySystem.TrackingLeftLegEnabled && cachedSolver.LeftLeg.target != null);
+ SetLegWeight(cachedSolver.RightLeg, BodySystem.TrackingRightLegEnabled && cachedSolver.RightLeg.target != null);
}
else
{
avatarVRIK.enabled = false;
- avatarIKSolver.IKPositionWeight = 0f;
- avatarIKSolver.locomotion.weight = 0f;
+ cachedSolver.Solver.IKPositionWeight = 0f;
+ cachedSolver.Locomotion.weight = 0f;
- avatarIKSolver.leftLeg.useAnimatedBendNormal = false;
- avatarIKSolver.rightLeg.useAnimatedBendNormal = false;
- SetArmWeight(avatarIKSolver.leftArm, false);
- SetArmWeight(avatarIKSolver.rightArm, false);
- SetLegWeight(avatarIKSolver.leftLeg, false);
- SetLegWeight(avatarIKSolver.rightLeg, false);
+ cachedSolver.LeftLeg.useAnimatedBendNormal = false;
+ cachedSolver.RightLeg.useAnimatedBendNormal = false;
+ SetArmWeight(cachedSolver.LeftArm, false);
+ SetArmWeight(cachedSolver.RightArm, false);
+ SetLegWeight(cachedSolver.LeftLeg, false);
+ SetLegWeight(cachedSolver.RightLeg, false);
}
}
@@ -319,42 +165,26 @@ internal class DesktopVRIKSystem : MonoBehaviour
public void OnSetupAvatarDesktop(Animator animator)
{
- if (!Setting_Enabled) return;
+ if (!DesktopVRIK.EntryEnabled.Value) return;
// only run for humanoid avatars
if (animator != null && animator.avatar != null && animator.avatar.isHuman)
{
- CalibrateDesktopVRIK();
+ Calibrator.CalibrateDesktopVRIK(animator);
ResetDesktopVRIK();
}
}
- public bool OnSetupIKScaling(float scaleDifference)
+ public void OnSetupIKScaling(float scaleDifference)
{
- if (avatarVRIK == null) return false;
-
_scaleDifference = scaleDifference;
VRIKUtils.ApplyScaleToVRIK
(
avatarVRIK,
- _vrikInitialFootDistance,
- _vrikInitialStepThreshold,
- _vrikInitialStepHeight,
+ calibrationData,
_scaleDifference
);
-
- //VRIKUtils.SetFootsteps
- //(
- // avatarVRIK,
- // _vrikInitialFootPosLeft * _scaleDifference,
- // _vrikInitialFootPosRight * _scaleDifference,
- // _vrikInitialFootRotLeft,
- // _vrikInitialFootRotRight
- //);
-
- ResetDesktopVRIK();
- return true;
}
public void OnPlayerSetupUpdate(bool isEmotePlaying)
@@ -367,13 +197,13 @@ internal class DesktopVRIKSystem : MonoBehaviour
// Disable tracking completely while emoting
BodySystem.TrackingEnabled = !isEmotePlaying;
- avatarIKSolver.Reset();
+ IKResetSolver();
ResetDesktopVRIK();
}
public void OnPlayerSetupSetSitting()
{
- avatarIKSolver.Reset();
+ IKResetSolver();
ResetDesktopVRIK();
}
@@ -398,7 +228,7 @@ internal class DesktopVRIKSystem : MonoBehaviour
if (_movementParent == currentParent)
{
// Add platform motion to IK solver
- avatarIKSolver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot);
+ cachedSolver.Solver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot);
ResetDesktopVRIK();
}
@@ -406,80 +236,88 @@ internal class DesktopVRIKSystem : MonoBehaviour
_movementParent = currentParent;
_movementPosition = currentPosition;
_movementRotation = currentRotation;
-
return;
}
-
- // if not for movementparent, reset ik solver
- avatarIKSolver.Reset();
+
+ // if not for movementparent, reset ik
+ IKResetSolver();
+ IKResetFootsteps();
ResetDesktopVRIK();
- //IKResetFootsteps();
}
public void OnPreSolverUpdate()
{
// Set plant feet
- avatarIKSolver.plantFeet = Setting_PlantFeet;
+ cachedSolver.Solver.plantFeet = DesktopVRIK.EntryPlantFeet.Value;
// Apply custom VRIK solving effects
IKBodyLeaningOffset(_ikWeightLerp);
IKBodyHeadingOffset(_ikWeightLerp);
+
+ void IKBodyLeaningOffset(float weight)
+ {
+ // Emulate old VRChat hip movement
+ if (DesktopVRIK.EntryBodyLeanWeight.Value <= 0) return;
+
+ if (DesktopVRIK.EntryProneThrusting.Value) weight = 1f;
+ float weightedAngle = DesktopVRIK.EntryBodyLeanWeight.Value * weight;
+ float angle = _cameraTransform.localEulerAngles.x;
+ angle = angle > 180 ? angle - 360 : angle;
+ Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, avatarTransform.right);
+ cachedSolver.Spine.headRotationOffset *= rotation;
+ }
+
+ void IKBodyHeadingOffset(float weight)
+ {
+ // Make root heading follow within a set limit
+ if (DesktopVRIK.EntryBodyHeadingLimit.Value <= 0) return;
+
+ float weightedAngleLimit = DesktopVRIK.EntryBodyHeadingLimit.Value * weight;
+ float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _ikSimulatedRootAngle);
+ float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot);
+
+ if (absDeltaAngleRoot > weightedAngleLimit)
+ {
+ deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit;
+ _ikSimulatedRootAngle = Mathf.MoveTowardsAngle(_ikSimulatedRootAngle, transform.eulerAngles.y, absDeltaAngleRoot - weightedAngleLimit);
+ }
+
+ cachedSolver.Spine.rootHeadingOffset = deltaAngleRoot;
+
+ if (DesktopVRIK.EntryPelvisHeadingWeight.Value > 0)
+ {
+ cachedSolver.Spine.pelvisRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * DesktopVRIK.EntryPelvisHeadingWeight.Value, 0f);
+ cachedSolver.Spine.chestRotationOffset *= Quaternion.Euler(0f, -deltaAngleRoot * DesktopVRIK.EntryPelvisHeadingWeight.Value, 0f);
+ }
+
+ if (DesktopVRIK.EntryChestHeadingWeight.Value > 0)
+ {
+ cachedSolver.Spine.chestRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * DesktopVRIK.EntryChestHeadingWeight.Value, 0f);
+ }
+ }
}
- void IKBodyLeaningOffset(float weight)
+ public void OnPostSolverUpdate()
{
- // Emulate old VRChat hip movement
- if (Setting_BodyLeanWeight <= 0) return;
-
- if (Setting_ProneThrusting) weight = 1f;
- float weightedAngle = Setting_BodyLeanWeight * weight;
- float angle = _cameraTransform.localEulerAngles.x;
- angle = angle > 180 ? angle - 360 : angle;
- Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, avatarTransform.right);
- avatarIKSolver.spine.headRotationOffset *= rotation;
+ if (!DesktopVRIK.EntryNetIKPass.Value) return;
+ Calibrator.ApplyNetIKPass();
}
- void IKBodyHeadingOffset(float weight)
+ void IKResetSolver()
{
- // Make root heading follow within a set limit
- if (Setting_BodyHeadingLimit <= 0) return;
-
- float weightedAngleLimit = Setting_BodyHeadingLimit * weight;
- float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _ikSimulatedRootAngle);
- float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot);
-
- if (absDeltaAngleRoot > weightedAngleLimit)
- {
- deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit;
- _ikSimulatedRootAngle = Mathf.MoveTowardsAngle(_ikSimulatedRootAngle, transform.eulerAngles.y, absDeltaAngleRoot - weightedAngleLimit);
- }
-
- avatarIKSolver.spine.rootHeadingOffset = deltaAngleRoot;
-
- if (Setting_PelvisHeadingWeight > 0)
- {
- avatarIKSolver.spine.pelvisRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_PelvisHeadingWeight, 0f);
- avatarIKSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, -deltaAngleRoot * Setting_PelvisHeadingWeight, 0f);
- }
-
- if (Setting_ChestHeadingWeight > 0)
- {
- avatarIKSolver.spine.chestRotationOffset *= Quaternion.Euler(0f, deltaAngleRoot * Setting_ChestHeadingWeight, 0f);
- }
+ cachedSolver.Solver.Reset();
}
void IKResetFootsteps()
{
// Reset footsteps immediatly to initial
- if (!Setting_ResetFootsteps) return;
+ if (!DesktopVRIK.EntryResetFootstepsOnIdle.Value) return;
- VRIKUtils.SetFootsteps
+ VRIKUtils.ResetToInitialFootsteps
(
avatarVRIK,
- _vrikInitialFootPosLeft,
- _vrikInitialFootPosRight,
- _vrikInitialFootRotLeft,
- _vrikInitialFootRotRight
+ calibrationData,
+ _scaleDifference
);
}
@@ -487,234 +325,4 @@ internal class DesktopVRIKSystem : MonoBehaviour
{
_ikSimulatedRootAngle = transform.eulerAngles.y;
}
-
- void CalibrateDesktopVRIK()
- {
- ScanAvatar();
- SetupVRIK();
- CalibrateVRIK();
- ConfigureVRIK();
- }
-
- void ScanAvatar()
- {
- // Find required avatar components
- avatarDescriptor = playerSetup._avatarDescriptor;
- avatarAnimator = playerSetup._animator;
- avatarTransform = playerSetup._avatar.transform;
- avatarLookAtIK = playerSetup.lookIK;
-
- // Get animator layer inticies
- _animIKPoseLayer = avatarAnimator.GetLayerIndex("IKPose");
- _animLocomotionLayer = avatarAnimator.GetLayerIndex("Locomotion/Emotes");
-
- // Dispose and create new _humanPoseHandler
- _humanPoseHandler?.Dispose();
- _humanPoseHandler = new HumanPoseHandler(avatarAnimator.avatar, avatarTransform);
-
- // Get initial human poses
- _humanPoseHandler.GetHumanPose(ref _humanPose);
- _humanPoseHandler.GetHumanPose(ref _humanPoseInitial);
-
- // Dumb fix for rare upload issue
- _vrikFixTransformsRequired = !avatarAnimator.enabled;
-
- // Find available HumanoidBodyBones
- BoneExists.Clear();
- foreach (HumanBodyBones bone in Enum.GetValues(typeof(HumanBodyBones)))
- {
- if (bone != HumanBodyBones.LastBone)
- {
- BoneExists.Add(bone, avatarAnimator.GetBoneTransform(bone) != null);
- }
- }
- }
-
- void SetupVRIK()
- {
- // Add and configure VRIK
- avatarVRIK = avatarTransform.AddComponentIfMissing();
- avatarVRIK.AutoDetectReferences();
- avatarIKSolver = avatarVRIK.solver;
-
- VRIKUtils.ConfigureVRIKReferences(avatarVRIK, Setting_UseVRIKToes);
-
- // Fix animator issue
- avatarVRIK.fixTransforms = _vrikFixTransformsRequired;
-
- // Default solver settings
- avatarIKSolver.locomotion.weight = 0f;
- avatarIKSolver.locomotion.angleThreshold = 30f;
- avatarIKSolver.locomotion.maxLegStretch = 1f;
- avatarIKSolver.spine.minHeadHeight = 0f;
- avatarIKSolver.IKPositionWeight = 1f;
- avatarIKSolver.spine.chestClampWeight = 0f;
- avatarIKSolver.spine.maintainPelvisPosition = 0f;
-
- // Body leaning settings
- avatarIKSolver.spine.bodyPosStiffness = 1f;
- avatarIKSolver.spine.bodyRotStiffness = 0.2f;
- // this is a hack, allows chest to rotate slightly
- // independent from hip rotation. Funny Spine.Solve()->Bend()
- avatarIKSolver.spine.neckStiffness = 0.0001f;
-
- // Disable locomotion
- // Setting velocity to 0 aleviated nameplate jitter issue on remote
- avatarIKSolver.locomotion.velocityFactor = 0f;
- avatarIKSolver.locomotion.maxVelocity = 0f;
- avatarIKSolver.locomotion.rootSpeed = 1000f;
-
- // Disable chest rotation by hands
- // this fixed Effector, Player Arm Movement, BetterInteractDesktop, ect
- // from making entire body shake, as well as while running
- avatarIKSolver.spine.rotateChestByHands = 0f;
-
- // Prioritize LookAtIK
- avatarIKSolver.spine.headClampWeight = 0.2f;
-
- // Disable going on tippytoes
- avatarIKSolver.spine.positionWeight = 0f;
- avatarIKSolver.spine.rotationWeight = 1f;
-
- // Set so emotes play properly
- avatarIKSolver.spine.maxRootAngle = 180f;
- // this is different in VR, as CVR player controller is not set up optimally for VRIK.
- // Desktop avatar rotates 1:1 with _PlayerLocal. VR has a disconnect because you can turn IRL.
-
- // We disable these ourselves now, as we no longer use BodySystem
- avatarIKSolver.spine.maintainPelvisPosition = 1f;
- avatarIKSolver.spine.positionWeight = 0f;
- avatarIKSolver.spine.pelvisPositionWeight = 0f;
- avatarIKSolver.leftArm.positionWeight = 0f;
- avatarIKSolver.leftArm.rotationWeight = 0f;
- avatarIKSolver.rightArm.positionWeight = 0f;
- avatarIKSolver.rightArm.rotationWeight = 0f;
- avatarIKSolver.leftLeg.positionWeight = 0f;
- avatarIKSolver.leftLeg.rotationWeight = 0f;
- avatarIKSolver.rightLeg.positionWeight = 0f;
- avatarIKSolver.rightLeg.rotationWeight = 0f;
-
- // This is now our master Locomotion weight
- avatarIKSolver.locomotion.weight = 1f;
- avatarIKSolver.IKPositionWeight = 1f;
- }
-
- void CalibrateVRIK()
- {
- SetAvatarPose(AvatarPose.Default);
-
- // Calculate bend normals with motorcycle pose
- VRIKUtils.CalculateKneeBendNormals(avatarVRIK, out _vrikKneeNormalLeft, out _vrikKneeNormalRight);
-
- SetAvatarPose(AvatarPose.IKPose);
-
- _vrikInitialHeadHeight = Mathf.Abs(avatarVRIK.references.head.position.y - avatarVRIK.references.rightFoot.position.y);
-
- // Calculate initial IK scaling values with IKPose
- VRIKUtils.CalculateInitialIKScaling(avatarVRIK, out _vrikInitialFootDistance, out _vrikInitialStepThreshold, out _vrikInitialStepHeight);
-
- // Calculate initial Footstep positions
- VRIKUtils.CalculateInitialFootsteps(avatarVRIK, out _vrikInitialFootPosLeft, out _vrikInitialFootPosRight, out _vrikInitialFootRotLeft, out _vrikInitialFootRotRight);
-
- // Setup HeadIKTarget
- VRIKUtils.SetupHeadIKTarget(avatarVRIK);
-
- // Initiate VRIK manually
- VRIKUtils.InitiateVRIKSolver(avatarVRIK);
-
- SetAvatarPose(AvatarPose.Initial);
- }
-
- void ConfigureVRIK()
- {
- // Reset scale diffrence
- _scaleDifference = 1f;
- VRIKUtils.ApplyScaleToVRIK
- (
- avatarVRIK,
- _vrikInitialFootDistance,
- _vrikInitialStepThreshold,
- _vrikInitialStepHeight,
- 1f
- );
- VRIKUtils.ApplyKneeBendNormals(avatarVRIK, _vrikKneeNormalLeft, _vrikKneeNormalRight);
- avatarVRIK.onPreSolverUpdate.AddListener(new UnityAction(DesktopVRIKSystem.Instance.OnPreSolverUpdate));
- }
-
- void SetAvatarPose(AvatarPose pose)
- {
- switch (pose)
- {
- case AvatarPose.Default:
- SetMusclesToValue(0f);
- break;
- case AvatarPose.Initial:
- if (HasCustomIKPose())
- {
- SetCustomLayersWeights(0f, 1f);
- return;
- }
- _humanPoseHandler.SetHumanPose(ref _humanPoseInitial);
- break;
- case AvatarPose.IKPose:
- if (HasCustomIKPose())
- {
- SetCustomLayersWeights(1f, 0f);
- return;
- }
- SetMusclesToPose(IKPoseMuscles);
- break;
- case AvatarPose.TPose:
- SetMusclesToPose(BodySystem.TPoseMuscles);
- break;
- default:
- break;
- }
- }
-
- bool HasCustomIKPose()
- {
- return _animLocomotionLayer != -1 && _animIKPoseLayer != -1;
- }
-
- void SetCustomLayersWeights(float customIKPoseLayerWeight, float locomotionLayerWeight)
- {
- avatarAnimator.SetLayerWeight(_animIKPoseLayer, customIKPoseLayerWeight);
- avatarAnimator.SetLayerWeight(_animLocomotionLayer, locomotionLayerWeight);
- avatarAnimator.Update(0f);
- }
-
- void SetMusclesToValue(float value)
- {
- _humanPoseHandler.GetHumanPose(ref _humanPose);
-
- for (int i = 0; i < _humanPose.muscles.Length; i++)
- {
- ApplyMuscleValue((MuscleIndex)i, value, ref _humanPose.muscles);
- }
-
- _humanPose.bodyRotation = Quaternion.identity;
- _humanPoseHandler.SetHumanPose(ref _humanPose);
- }
-
- void SetMusclesToPose(float[] muscles)
- {
- _humanPoseHandler.GetHumanPose(ref _humanPose);
-
- for (int i = 0; i < _humanPose.muscles.Length; i++)
- {
- ApplyMuscleValue((MuscleIndex)i, muscles[i], ref _humanPose.muscles);
- }
-
- _humanPose.bodyRotation = Quaternion.identity;
- _humanPoseHandler.SetHumanPose(ref _humanPose);
- }
-
- void ApplyMuscleValue(MuscleIndex index, float value, ref float[] muscles)
- {
- if (BoneExists.ContainsKey(IKSystem.MusclesToHumanBodyBones[(int)index]) && BoneExists[IKSystem.MusclesToHumanBodyBones[(int)index]])
- {
- muscles[(int)index] = value;
- }
- }
}
\ No newline at end of file
diff --git a/DesktopVRIK/Integrations/BTKUIAddon.cs b/DesktopVRIK/Integrations/BTKUIAddon.cs
index 45cfa3e..d2e0b45 100644
--- a/DesktopVRIK/Integrations/BTKUIAddon.cs
+++ b/DesktopVRIK/Integrations/BTKUIAddon.cs
@@ -2,7 +2,7 @@
using BTKUILib.UIObjects;
using System.Runtime.CompilerServices;
-namespace NAK.DesktopVRIK;
+namespace NAK.DesktopVRIK.Integrations;
public static class BTKUIAddon
{
diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs
index bb72dae..309ab33 100644
--- a/DesktopVRIK/Main.cs
+++ b/DesktopVRIK/Main.cs
@@ -1,5 +1,4 @@
using MelonLoader;
-using UnityEngine;
namespace NAK.DesktopVRIK;
@@ -8,41 +7,44 @@ public class DesktopVRIK : MelonMod
internal static MelonLogger.Instance Logger;
internal const string SettingsCategory = nameof(DesktopVRIK);
- public static readonly MelonPreferences_Category CategoryDesktopVRIK =
+ public static readonly MelonPreferences_Category Category =
MelonPreferences.CreateCategory(SettingsCategory);
public static readonly MelonPreferences_Entry EntryEnabled =
- CategoryDesktopVRIK.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload.");
+ Category.CreateEntry("Enabled", true, description: "Toggle DesktopVRIK entirely. Requires avatar reload.");
public static readonly MelonPreferences_Entry EntryPlantFeet =
- CategoryDesktopVRIK.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled to prevent hovering when stopping movement.");
+ Category.CreateEntry("Enforce Plant Feet", true, description: "Forces VRIK Plant Feet enabled to prevent hovering when stopping movement.");
public static readonly MelonPreferences_Entry EntryResetFootstepsOnIdle =
- CategoryDesktopVRIK.CreateEntry("Reset Footsteps on Idle", true, description: "Determins if the Locomotion Footsteps will be reset to their calibration position when entering idle.");
+ Category.CreateEntry("Reset Footsteps on Idle", false, description: "Determins if the Locomotion Footsteps will be reset to their calibration position when entering idle.");
public static readonly MelonPreferences_Entry EntryUseVRIKToes =
- CategoryDesktopVRIK.CreateEntry("Use VRIK Toes", false, description: "Determines if VRIK uses humanoid toes for IK solving, which can cause feet to idle behind the avatar.");
+ Category.CreateEntry("Use VRIK Toes", false, description: "Determines if VRIK uses humanoid toes for IK solving, which can cause feet to idle behind the avatar.");
public static readonly MelonPreferences_Entry EntryBodyLeanWeight =
- CategoryDesktopVRIK.CreateEntry("Body Lean Weight", 0.5f, description: "Adds rotational influence to the body solver when looking up/down. Set to 0 to disable.");
+ Category.CreateEntry("Body Lean Weight", 0.5f, description: "Adds rotational influence to the body solver when looking up/down. Set to 0 to disable.");
public static readonly MelonPreferences_Entry EntryBodyHeadingLimit =
- CategoryDesktopVRIK.CreateEntry("Body Heading Limit", 20f, description: "Specifies the maximum angle the lower body can have relative to the head when rotating. Set to 0 to disable.");
+ Category.CreateEntry("Body Heading Limit", 20f, description: "Specifies the maximum angle the lower body can have relative to the head when rotating. Set to 0 to disable.");
public static readonly MelonPreferences_Entry EntryPelvisHeadingWeight =
- CategoryDesktopVRIK.CreateEntry("Pelvis Heading Weight", 0.25f, description: "Determines how much the pelvis will face the Body Heading Limit. Set to 0 to align with head.");
+ Category.CreateEntry("Pelvis Heading Weight", 0.25f, description: "Determines how much the pelvis will face the Body Heading Limit. Set to 0 to align with head.");
public static readonly MelonPreferences_Entry EntryChestHeadingWeight =
- CategoryDesktopVRIK.CreateEntry("Chest Heading Weight", 0.75f, description: "Determines how much the chest will face the Body Heading Limit. Set to 0 to align with head.");
+ Category.CreateEntry("Chest Heading Weight", 0.75f, description: "Determines how much the chest will face the Body Heading Limit. Set to 0 to align with head.");
public static readonly MelonPreferences_Entry EntryIKLerpSpeed =
- CategoryDesktopVRIK.CreateEntry("IK Lerp Speed", 10f, description: "Determines fast the IK & Locomotion weights blend after entering idle. Set to 0 to disable.");
+ Category.CreateEntry("IK Lerp Speed", 10f, description: "Determines fast the IK & Locomotion weights blend after entering idle. Set to 0 to disable.");
public static readonly MelonPreferences_Entry EntryProneThrusting =
- CategoryDesktopVRIK.CreateEntry("Prone Thrusting", false, description: "Allows Body Lean Weight to take effect while crouched or prone.");
+ Category.CreateEntry("Prone Thrusting", false, description: "Allows Body Lean Weight to take effect while crouched or prone.");
+
+ public static readonly MelonPreferences_Entry EntryNetIKPass =
+ Category.CreateEntry("Network IK Pass", true, description: "Should NetIK pass be applied? This fixes a bunch of small rotation errors after VRIK is run.");
public static readonly MelonPreferences_Entry EntryIntegrationAMT =
- CategoryDesktopVRIK.CreateEntry("AMT Integration", true, description: "Relies on AvatarMotionTweaker to handle VRIK Locomotion weights if available.");
+ Category.CreateEntry("AMT Integration", true, description: "Relies on AvatarMotionTweaker to handle VRIK Locomotion weights if available.");
public static bool integration_AMT = false;
@@ -50,57 +52,27 @@ public class DesktopVRIK : MelonMod
{
Logger = LoggerInstance;
- CategoryDesktopVRIK.Entries.ForEach(e => e.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings));
-
- ApplyPatches(typeof(HarmonyPatches.PlayerSetupPatches));
-
//BTKUILib Misc Tab
if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib"))
{
Logger.Msg("Initializing BTKUILib support.");
- BTKUIAddon.Init();
+ Integrations.BTKUIAddon.Init();
}
+
//AvatarMotionTweaker Handling
if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "AvatarMotionTweaker"))
{
- Logger.Msg("AvatarMotionTweaker was found. Relying on it to handle VRIK locomotion.");
integration_AMT = true;
+ Logger.Msg("AvatarMotionTweaker was found. Relying on it to handle VRIK locomotion.");
}
else
{
Logger.Msg("AvatarMotionTweaker was not found. Using built-in VRIK locomotion handling.");
}
+
+ ApplyPatches(typeof(HarmonyPatches.PlayerSetupPatches));
}
- internal static void UpdateAllSettings()
- {
- if (!DesktopVRIKSystem.Instance) return;
- // DesktopVRIK Settings
- DesktopVRIKSystem.Instance.Setting_Enabled = EntryEnabled.Value;
- DesktopVRIKSystem.Instance.Setting_PlantFeet = EntryPlantFeet.Value;
- DesktopVRIKSystem.Instance.Setting_ResetFootsteps = EntryResetFootstepsOnIdle.Value;
-
- DesktopVRIKSystem.Instance.Setting_BodyLeanWeight = Mathf.Clamp01(EntryBodyLeanWeight.Value);
- DesktopVRIKSystem.Instance.Setting_BodyHeadingLimit = Mathf.Clamp(EntryBodyHeadingLimit.Value, 0f, 90f);
- DesktopVRIKSystem.Instance.Setting_PelvisHeadingWeight = (1f - Mathf.Clamp01(EntryPelvisHeadingWeight.Value));
- DesktopVRIKSystem.Instance.Setting_ChestHeadingWeight = (1f - Mathf.Clamp01(EntryChestHeadingWeight.Value));
- DesktopVRIKSystem.Instance.Setting_ChestHeadingWeight = (1f - Mathf.Clamp01(EntryChestHeadingWeight.Value));
- DesktopVRIKSystem.Instance.Setting_IKLerpSpeed = Mathf.Clamp(EntryIKLerpSpeed.Value, 0f, 20f);
-
- // Calibration Settings
- DesktopVRIKSystem.Instance.Setting_UseVRIKToes = EntryUseVRIKToes.Value;
-
- // Fine-tuning Settings
- DesktopVRIKSystem.Instance.Setting_ResetFootsteps = EntryResetFootstepsOnIdle.Value;
-
- // Integration Settings
- DesktopVRIKSystem.Instance.Setting_IntegrationAMT = EntryIntegrationAMT.Value && integration_AMT;
-
- // Funny Settings
- DesktopVRIKSystem.Instance.Setting_ProneThrusting = EntryProneThrusting.Value;
- }
- void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings();
-
void ApplyPatches(Type type)
{
try
diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs
index 61ac95a..c35a721 100644
--- a/DesktopVRIK/Properties/AssemblyInfo.cs
+++ b/DesktopVRIK/Properties/AssemblyInfo.cs
@@ -26,6 +26,6 @@ using System.Reflection;
namespace NAK.DesktopVRIK.Properties;
internal static class AssemblyInfoParams
{
- public const string Version = "4.1.8";
+ public const string Version = "4.2.0";
public const string Author = "NotAKidoS";
}
\ No newline at end of file
diff --git a/DesktopVRIK/VRIKHelpers/CachedSolver.cs b/DesktopVRIK/VRIKHelpers/CachedSolver.cs
new file mode 100644
index 0000000..2b651f1
--- /dev/null
+++ b/DesktopVRIK/VRIKHelpers/CachedSolver.cs
@@ -0,0 +1,28 @@
+using RootMotion.FinalIK;
+
+namespace NAK.DesktopVRIK.VRIKHelper;
+
+// I don't think this was needed at all, but it looks fancy.
+//https://github.com/knah/VRCMods/blob/master/IKTweaks/CachedSolver.cs
+
+public struct CachedSolver
+{
+ public readonly IKSolverVR Solver;
+ public readonly IKSolverVR.Spine Spine;
+ public readonly IKSolverVR.Leg LeftLeg;
+ public readonly IKSolverVR.Leg RightLeg;
+ public readonly IKSolverVR.Arm LeftArm;
+ public readonly IKSolverVR.Arm RightArm;
+ public readonly IKSolverVR.Locomotion Locomotion;
+
+ public CachedSolver(IKSolverVR solver)
+ {
+ Solver = solver;
+ Spine = solver.spine;
+ LeftArm = solver.leftArm;
+ LeftLeg = solver.leftLeg;
+ RightArm = solver.rightArm;
+ RightLeg = solver.rightLeg;
+ Locomotion = solver.locomotion;
+ }
+}
\ No newline at end of file
diff --git a/DesktopVRIK/VRIKHelpers/VRIKCalibrationData.cs b/DesktopVRIK/VRIKHelpers/VRIKCalibrationData.cs
new file mode 100644
index 0000000..f06ae46
--- /dev/null
+++ b/DesktopVRIK/VRIKHelpers/VRIKCalibrationData.cs
@@ -0,0 +1,33 @@
+using UnityEngine;
+
+namespace NAK.DesktopVRIK.VRIKHelper;
+
+public struct VRIKCalibrationData
+{
+ 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 bool FixTransformsRequired;
+
+ 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;
+ FixTransformsRequired = false;
+ }
+}
\ No newline at end of file
diff --git a/DesktopVRIK/VRIKHelpers/VRIKConfiguration.cs b/DesktopVRIK/VRIKHelpers/VRIKConfiguration.cs
new file mode 100644
index 0000000..85d783c
--- /dev/null
+++ b/DesktopVRIK/VRIKHelpers/VRIKConfiguration.cs
@@ -0,0 +1,87 @@
+namespace NAK.DesktopVRIK.VRIKHelper;
+
+public class VRIKConfiguration
+{
+ // Solver settings
+ public float LocomotionWeight { get; set; }
+ public float LocomotionAngleThreshold { get; set; }
+ public float LocomotionMaxLegStretch { get; set; }
+ public float SpineMinHeadHeight { get; set; }
+ public float SolverIKPositionWeight { get; set; }
+ public float SpineChestClampWeight { get; set; }
+ public float SpineMaintainPelvisPosition { get; set; }
+
+ // Body leaning settings
+ public float SpineBodyPosStiffness { get; set; }
+ public float SpineBodyRotStiffness { get; set; }
+ public float SpineNeckStiffness { get; set; }
+
+ // Locomotion settings
+ public float LocomotionVelocityFactor { get; set; }
+ public float LocomotionMaxVelocity { get; set; }
+ public float LocomotionRootSpeed { get; set; }
+
+ // Chest rotation
+ public float SpineRotateChestByHands { get; set; }
+
+ public float SpineHeadClampWeight { get; set; }
+
+ public float SpinePositionWeight { get; set; }
+ public float SpineRotationWeight { get; set; }
+
+ public float SpineMaxRootAngle { get; set; }
+
+ // BodySystem
+ public float SpinePelvisPositionWeight { get; set; }
+ public float LeftArmPositionWeight { get; set; }
+ public float LeftArmRotationWeight { get; set; }
+ public float RightArmPositionWeight { get; set; }
+ public float RightArmRotationWeight { get; set; }
+ public float LeftLegPositionWeight { get; set; }
+ public float LeftLegRotationWeight { get; set; }
+ public float RightLegPositionWeight { get; set; }
+ public float RightLegRotationWeight { get; set; }
+}
+
+public static class VRIKConfigurator
+{
+ public static void ApplyVRIKConfiguration(CachedSolver cachedSolver, VRIKConfiguration config)
+ {
+ cachedSolver.Solver.IKPositionWeight = config.SolverIKPositionWeight;
+ cachedSolver.Locomotion.weight = config.LocomotionWeight;
+ cachedSolver.Locomotion.angleThreshold = config.LocomotionAngleThreshold;
+ cachedSolver.Locomotion.maxLegStretch = config.LocomotionMaxLegStretch;
+
+ cachedSolver.Spine.chestClampWeight = config.SpineChestClampWeight;
+ cachedSolver.Spine.maintainPelvisPosition = config.SpineMaintainPelvisPosition;
+ cachedSolver.Spine.minHeadHeight = config.SpineMinHeadHeight;
+
+ cachedSolver.Spine.bodyPosStiffness = config.SpineBodyPosStiffness;
+ cachedSolver.Spine.bodyRotStiffness = config.SpineBodyRotStiffness;
+ cachedSolver.Spine.neckStiffness = config.SpineNeckStiffness;
+
+ cachedSolver.Locomotion.velocityFactor = config.LocomotionVelocityFactor;
+ cachedSolver.Locomotion.maxVelocity = config.LocomotionMaxVelocity;
+ cachedSolver.Locomotion.rootSpeed = config.LocomotionRootSpeed;
+
+ cachedSolver.Spine.rotateChestByHands = config.SpineRotateChestByHands;
+
+ cachedSolver.Spine.headClampWeight = config.SpineHeadClampWeight;
+
+ cachedSolver.Spine.positionWeight = config.SpinePositionWeight;
+ cachedSolver.Spine.rotationWeight = config.SpineRotationWeight;
+
+ cachedSolver.Spine.maxRootAngle = config.SpineMaxRootAngle;
+
+ cachedSolver.Spine.maintainPelvisPosition = config.SpineMaintainPelvisPosition;
+ cachedSolver.Spine.pelvisPositionWeight = config.SpinePelvisPositionWeight;
+ cachedSolver.LeftArm.positionWeight = config.LeftArmPositionWeight;
+ cachedSolver.LeftArm.rotationWeight = config.LeftArmRotationWeight;
+ cachedSolver.RightArm.positionWeight = config.RightArmPositionWeight;
+ cachedSolver.RightArm.rotationWeight = config.RightArmRotationWeight;
+ cachedSolver.LeftLeg.positionWeight = config.LeftLegPositionWeight;
+ cachedSolver.LeftLeg.rotationWeight = config.LeftLegRotationWeight;
+ cachedSolver.RightLeg.positionWeight = config.RightLegPositionWeight;
+ cachedSolver.RightLeg.rotationWeight = config.RightLegRotationWeight;
+ }
+}
\ No newline at end of file
diff --git a/DesktopVRIK/VRIKHelpers/VRIKConfigurations.cs b/DesktopVRIK/VRIKHelpers/VRIKConfigurations.cs
new file mode 100644
index 0000000..b412460
--- /dev/null
+++ b/DesktopVRIK/VRIKHelpers/VRIKConfigurations.cs
@@ -0,0 +1,53 @@
+namespace NAK.DesktopVRIK.VRIKHelper;
+
+public static class VRIKConfigurations
+{
+ public static VRIKConfiguration DesktopVRIKConfiguration()
+ {
+ return new VRIKConfiguration
+ {
+ // Solver settings
+ LocomotionWeight = 0f,
+ LocomotionAngleThreshold = 30f,
+ LocomotionMaxLegStretch = 1f,
+ SpineMinHeadHeight = 0f,
+ SolverIKPositionWeight = 1f,
+ SpineChestClampWeight = 0f,
+ SpineMaintainPelvisPosition = 1f,
+
+ // Body leaning settings
+ SpineBodyPosStiffness = 1f,
+ SpineBodyRotStiffness = 0.2f,
+ SpineNeckStiffness = 0.0001f, //hack
+
+ // Locomotion settings
+ LocomotionVelocityFactor = 0f,
+ LocomotionMaxVelocity = 0f,
+ LocomotionRootSpeed = 1000f,
+
+ // Chest rotation
+ SpineRotateChestByHands = 0f, //pam, bid, leap motion change
+
+ // LookAtIK priority
+ SpineHeadClampWeight = 0.2f,
+
+ // Tippytoes
+ SpinePositionWeight = 0f,
+ SpineRotationWeight = 1f,
+
+ // Emotes
+ SpineMaxRootAngle = 180f,
+
+ // BodySystem
+ SpinePelvisPositionWeight = 0f,
+ LeftArmPositionWeight = 0f,
+ LeftArmRotationWeight = 0f,
+ RightArmPositionWeight = 0f,
+ RightArmRotationWeight = 0f,
+ LeftLegPositionWeight = 0f,
+ LeftLegRotationWeight = 0f,
+ RightLegPositionWeight = 0f,
+ RightLegRotationWeight = 0f,
+ };
+ }
+}
\ No newline at end of file
diff --git a/DesktopVRIK/VRIKUtils.cs b/DesktopVRIK/VRIKHelpers/VRIKUtils.cs
similarity index 59%
rename from DesktopVRIK/VRIKUtils.cs
rename to DesktopVRIK/VRIKHelpers/VRIKUtils.cs
index 53ef94b..ec3288d 100644
--- a/DesktopVRIK/VRIKUtils.cs
+++ b/DesktopVRIK/VRIKHelpers/VRIKUtils.cs
@@ -1,15 +1,12 @@
using RootMotion.FinalIK;
using UnityEngine;
-namespace NAK.DesktopVRIK;
+namespace NAK.DesktopVRIK.VRIKHelper;
public static class VRIKUtils
{
public static void ConfigureVRIKReferences(VRIK vrik, bool useVRIKToes)
{
- //might not work over netik
- //FixChestAndSpineReferences(vrik);
-
if (!useVRIKToes)
{
vrik.references.leftToes = null;
@@ -20,36 +17,22 @@ public static class VRIKUtils
FixFingerBonesError(vrik);
}
- private static void FixChestAndSpineReferences(VRIK vrik)
- {
- Transform leftShoulderBone = vrik.references.leftShoulder;
- Transform rightShoulderBone = vrik.references.rightShoulder;
- Transform assumedChest = leftShoulderBone?.parent;
-
- if (assumedChest != null && rightShoulderBone.parent == assumedChest &&
- vrik.references.chest != assumedChest)
- {
- vrik.references.chest = assumedChest;
- vrik.references.spine = assumedChest.parent;
- }
- }
-
private static void FixFingerBonesError(VRIK vrik)
{
+ void FixFingerBones(VRIK vrik, Transform hand, IKSolverVR.Arm armSolver)
+ {
+ if (hand.childCount == 0)
+ {
+ armSolver.wristToPalmAxis = Vector3.up;
+ armSolver.palmToThumbAxis = hand == vrik.references.leftHand ? -Vector3.forward : Vector3.forward;
+ }
+ }
+
FixFingerBones(vrik, vrik.references.leftHand, vrik.solver.leftArm);
FixFingerBones(vrik, vrik.references.rightHand, vrik.solver.rightArm);
}
- private static void FixFingerBones(VRIK vrik, Transform hand, IKSolverVR.Arm armSolver)
- {
- if (hand.childCount == 0)
- {
- armSolver.wristToPalmAxis = Vector3.up;
- armSolver.palmToThumbAxis = hand == vrik.references.leftHand ? -Vector3.forward : Vector3.forward;
- }
- }
-
- public static void CalculateKneeBendNormals(VRIK vrik, out Vector3 leftKneeNormal, out Vector3 rightKneeNormal)
+ 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;
@@ -60,7 +43,7 @@ public static class VRIKUtils
GetPositionOrDefault(vrik.references.leftCalf),
GetPositionOrDefault(vrik.references.leftFoot)
};
- leftKneeNormal = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(leftVectors);
+ calibrationData.KneeNormalLeft = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(leftVectors);
// Get assumed right knee normal
Vector3[] rightVectors = {
@@ -68,10 +51,10 @@ public static class VRIKUtils
GetPositionOrDefault(vrik.references.rightCalf),
GetPositionOrDefault(vrik.references.rightFoot)
};
- rightKneeNormal = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(rightVectors);
+ calibrationData.KneeNormalRight = Quaternion.Inverse(vrik.references.root.rotation) * GetNormalFromArray(rightVectors);
}
- public static void ApplyKneeBendNormals(VRIK vrik, Vector3 leftKneeNormal, Vector3 rightKneeNormal)
+ public static void ApplyKneeBendNormals(VRIK vrik, VRIKCalibrationData calibrationData)
{
// 0 uses bendNormalRelToPelvis, 1 is bendNormalRelToTarget
// modifying pelvis normal weight is easier math
@@ -79,8 +62,8 @@ public static class VRIKUtils
vrik.solver.rightLeg.bendToTargetWeight = 0f;
var pelvis_localRotationInverse = Quaternion.Inverse(vrik.references.pelvis.localRotation);
- vrik.solver.leftLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * leftKneeNormal;
- vrik.solver.rightLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * rightKneeNormal;
+ vrik.solver.leftLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * calibrationData.KneeNormalLeft;
+ vrik.solver.rightLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * calibrationData.KneeNormalRight;
}
private static Vector3 GetNormalFromArray(Vector3[] positions)
@@ -102,17 +85,19 @@ public static class VRIKUtils
return normal.normalized;
}
- public static void CalculateInitialIKScaling(VRIK vrik, out float initialFootDistance, out float initialStepThreshold, out float initialStepHeight)
+ public static void CalculateInitialIKScaling(VRIK vrik, ref VRIKCalibrationData calibrationData)
{
// 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);
- initialFootDistance = footDistance * 0.5f;
- initialStepThreshold = footDistance * scaleModifier;
- initialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f;
+
+ 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);
}
- public static void CalculateInitialFootsteps(VRIK vrik, out Vector3 initialFootPosLeft, out Vector3 initialFootPosRight, out Quaternion initialFootRotLeft, out Quaternion initialFootRotRight)
+ public static void CalculateInitialFootsteps(VRIK vrik, ref VRIKCalibrationData calibrationData)
{
Transform root = vrik.references.root;
Transform leftFoot = vrik.references.leftFoot;
@@ -122,25 +107,26 @@ public static class VRIKUtils
Quaternion rootWorldRot = root.rotation;
// Calculate the world rotation of the left and right feet relative to the root bone
- initialFootPosLeft = root.InverseTransformPoint(leftFoot.position);
- initialFootPosRight = root.InverseTransformPoint(rightFoot.position);
- initialFootRotLeft = Quaternion.Inverse(rootWorldRot) * leftFoot.rotation;
- initialFootRotRight = Quaternion.Inverse(rootWorldRot) * rightFoot.rotation;
+ 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;
}
- public static void SetFootsteps(VRIK vrik, Vector3 footPosLeft, Vector3 footPosRight, Quaternion footRotLeft, Quaternion footRotRight)
+ public static void ResetToInitialFootsteps(VRIK vrik, VRIKCalibrationData calibrationData, float scaleModifier)
{
var locomotionSolver = vrik.solver.locomotion;
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(footPosLeft), rootWorldRot * footRotLeft);
- footstepRight.Reset(rootWorldRot, root.parent.TransformPoint(footPosRight), rootWorldRot * footRotRight);
+ footstepLeft.Reset(rootWorldRot, root.parent.TransformPoint(calibrationData.InitialFootPosLeft * scaleModifier), rootWorldRot * calibrationData.InitialFootRotLeft);
+ footstepRight.Reset(rootWorldRot, root.parent.TransformPoint(calibrationData.InitialFootPosRight * scaleModifier), rootWorldRot * calibrationData.InitialFootRotRight);
}
public static void SetupHeadIKTarget(VRIK vrik)
@@ -155,15 +141,15 @@ public static class VRIKUtils
vrik.solver.spine.headTarget.localRotation = Quaternion.identity;
}
- public static void ApplyScaleToVRIK(VRIK vrik, float footDistance, float stepThreshold, float stepHeight, float modifier)
+ public static void ApplyScaleToVRIK(VRIK vrik, VRIKCalibrationData calibrationData, float scaleModifier)
{
var locomotionSolver = vrik.solver.locomotion;
- locomotionSolver.footDistance = footDistance * modifier;
- locomotionSolver.stepThreshold = stepThreshold * modifier;
- ScaleStepHeight(locomotionSolver.stepHeight, stepHeight * modifier);
+ locomotionSolver.footDistance = calibrationData.InitialFootDistance * scaleModifier;
+ locomotionSolver.stepThreshold = calibrationData.InitialStepThreshold * scaleModifier;
+ ScaleStepHeight(locomotionSolver.stepHeight, calibrationData.InitialStepHeight * scaleModifier);
}
- private static void ScaleStepHeight(AnimationCurve stepHeightCurve, float mag)
+ static void ScaleStepHeight(AnimationCurve stepHeightCurve, float mag)
{
Keyframe[] keyframes = stepHeightCurve.keys;
keyframes[1].value = mag;