From 09cb3838a6425fc19447579bb41f8c4a729a1501 Mon Sep 17 00:00:00 2001 From: NotAKidoS <37721153+NotAKidOnSteam@users.noreply.github.com> Date: Thu, 30 Mar 2023 23:34:18 -0500 Subject: [PATCH] weight bump --- DesktopVRIK/DesktopVRIKSystem.cs | 106 +++++++++++++++---------- DesktopVRIK/Integrations/BTKUIAddon.cs | 17 ++-- DesktopVRIK/Main.cs | 32 +++++++- DesktopVRIK/Properties/AssemblyInfo.cs | 2 +- DesktopVRIK/VRIKUtils.cs | 29 ++++++- DesktopVRIK/format.json | 6 +- 6 files changed, 134 insertions(+), 58 deletions(-) diff --git a/DesktopVRIK/DesktopVRIKSystem.cs b/DesktopVRIK/DesktopVRIKSystem.cs index 0e06308..d6e0b53 100644 --- a/DesktopVRIK/DesktopVRIKSystem.cs +++ b/DesktopVRIK/DesktopVRIKSystem.cs @@ -123,19 +123,20 @@ internal class DesktopVRIKSystem : MonoBehaviour // DesktopVRIK Settings public bool Setting_Enabled = true; - public bool Setting_PlantFeet = true; + public bool Setting_PlantFeet; public bool Setting_ResetFootsteps; 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 = true; - public bool Setting_FindUnmappedToes = true; + public bool Setting_UseVRIKToes; + public bool Setting_FindUnmappedToes; // Integration Settings - public bool Setting_IntegrationAMT = false; + public bool Setting_IntegrationAMT; // Avatar Components public CVRAvatar avatarDescriptor = null; @@ -161,20 +162,21 @@ internal class DesktopVRIKSystem : MonoBehaviour // VRIK Calibration Info Vector3 _vrikKneeNormalLeft; Vector3 _vrikKneeNormalRight; - Vector3 _vrikInitialFootStepLeft; - Vector3 _vrikInitialFootStepRight; + Vector3 _vrikInitialFootPosLeft; + Vector3 _vrikInitialFootPosRight; + Quaternion _vrikInitialFootRotLeft; + Quaternion _vrikInitialFootRotRight; float _vrikInitialFootDistance; float _vrikInitialStepThreshold; float _vrikInitialStepHeight; bool _vrikFixTransformsRequired; // Player Info - Transform _cameraTransform = null; - bool _ikEmotePlaying = false; + Transform _cameraTransform; + bool _ikEmotePlaying; + float _ikWeightLerp = 1f; float _ikSimulatedRootAngle = 0f; float _locomotionWeight = 1f; - float _locomotionWeightLerp = 1f; - float _locomotionLerpSpeed = 10f; // Last Movement Parent Info Vector3 _movementPosition; @@ -202,32 +204,60 @@ internal class DesktopVRIKSystem : MonoBehaviour if (avatarVRIK == null) return; HandleLocomotionTracking(); - LerpLocomotionWeight(); + UpdateLocomotionWeight(); ApplyBodySystemWeights(); } void HandleLocomotionTracking() { - bool isMoving = movementSystem.movementVector.magnitude > 0f; - bool isGrounded = movementSystem._isGrounded; - bool isCrouching = movementSystem.crouching; - bool isProne = movementSystem.prone; - bool isFlying = movementSystem.flying; - - bool shouldTrackLocomotion = !(isMoving || isCrouching || isProne || isFlying || !isGrounded); + bool shouldTrackLocomotion = ShouldTrackLocomotion(); if (shouldTrackLocomotion != BodySystem.TrackingLocomotionEnabled) { BodySystem.TrackingLocomotionEnabled = shouldTrackLocomotion; avatarIKSolver.Reset(); ResetDesktopVRIK(); + if (shouldTrackLocomotion) IKResetFootsteps(); } } - void LerpLocomotionWeight() + bool ShouldTrackLocomotion() { - _locomotionWeight = BodySystem.TrackingEnabled && BodySystem.TrackingLocomotionEnabled ? 1.0f : 0.0f; - _locomotionWeightLerp = Mathf.Lerp(_locomotionWeightLerp, _locomotionWeight, Time.deltaTime * _locomotionLerpSpeed); + bool isMoving = movementSystem.movementVector.magnitude > 0f; + bool isGrounded = movementSystem._isGrounded; + bool isCrouching = movementSystem.crouching; + bool isProne = movementSystem.prone; + bool isFlying = movementSystem.flying; + bool isStanding = IsStanding(); + + return !(isMoving || isCrouching || isProne || isFlying || !isGrounded || !isStanding); + } + + bool IsStanding() + { + // Let AMT handle it if available + if (Setting_IntegrationAMT) return true; + + // Get Upright value + Vector3 delta = avatarIKSolver.spine.headPosition - avatarTransform.position; + Vector3 deltaRotated = Quaternion.Euler(0, avatarTransform.rotation.eulerAngles.y, 0) * delta; + float upright = Mathf.InverseLerp(0f, avatarIKSolver.spine.headHeight, deltaRotated.y); + return upright > 0.85f; + } + + void UpdateLocomotionWeight() + { + float targetWeight = BodySystem.TrackingEnabled && BodySystem.TrackingLocomotionEnabled ? 1.0f : 0.0f; + if (Setting_IKLerpSpeed > 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; + } } void ApplyBodySystemWeights() @@ -354,17 +384,11 @@ internal class DesktopVRIKSystem : MonoBehaviour avatarIKSolver.plantFeet = Setting_PlantFeet; // Apply custom VRIK solving effects - if (_locomotionWeightLerp > 0) + if (_ikWeightLerp > 0) { IKBodyLeaningOffset(); IKBodyHeadingOffset(); } - - // Reset footsteps while transitioning - if (_locomotionWeightLerp < 0.99f) - { - IKResetFootsteps(); - } } void IKBodyLeaningOffset() @@ -372,7 +396,7 @@ internal class DesktopVRIKSystem : MonoBehaviour // Emulate old VRChat hip movement if (Setting_BodyLeanWeight <= 0) return; - float weightedAngle = Setting_BodyLeanWeight * _locomotionWeightLerp; + float weightedAngle = Setting_BodyLeanWeight * _ikWeightLerp; float angle = _cameraTransform.localEulerAngles.x; angle = angle > 180 ? angle - 360 : angle; Quaternion rotation = Quaternion.AngleAxis(angle * weightedAngle, avatarTransform.right); @@ -384,7 +408,7 @@ internal class DesktopVRIKSystem : MonoBehaviour // Make root heading follow within a set limit if (Setting_BodyHeadingLimit <= 0) return; - float weightedAngleLimit = Setting_BodyHeadingLimit * _locomotionWeightLerp; + float weightedAngleLimit = Setting_BodyHeadingLimit * _ikWeightLerp; float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _ikSimulatedRootAngle); float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot); @@ -410,17 +434,17 @@ internal class DesktopVRIKSystem : MonoBehaviour void IKResetFootsteps() { - // Attempt to skip footstep transition + // Reset footsteps immediatly to initial if (!Setting_ResetFootsteps) return; - IKSolverVR.Footstep footstepLeft = avatarIKSolver.locomotion.footsteps[0]; - IKSolverVR.Footstep footstepRight = avatarIKSolver.locomotion.footsteps[1]; - Vector3 globalLeft = movementSystem.transform.TransformPoint(_vrikInitialFootStepLeft); - Vector3 globalRight = movementSystem.transform.TransformPoint(_vrikInitialFootStepRight); - footstepLeft.Reset(avatarTransform.rotation, globalLeft, footstepLeft.stepToRot); - footstepRight.Reset(avatarTransform.rotation, globalRight, footstepRight.stepToRot); - //footstepRight.StepTo(globalRight, avatarTransform.rotation, 100f); - //footstepLeft.StepTo(globalLeft, avatarTransform.rotation, 100f); + VRIKUtils.SetFootsteps + ( + avatarVRIK, + _vrikInitialFootPosLeft, + _vrikInitialFootPosRight, + _vrikInitialFootRotLeft, + _vrikInitialFootRotRight + ); } void ResetDesktopVRIK() @@ -542,7 +566,7 @@ internal class DesktopVRIKSystem : MonoBehaviour VRIKUtils.CalculateInitialIKScaling(avatarVRIK, out _vrikInitialFootDistance, out _vrikInitialStepThreshold, out _vrikInitialStepHeight); // Calculate initial Footstep positions - VRIKUtils.CalculateInitialFootsteps(avatarVRIK, out _vrikInitialFootStepLeft, out _vrikInitialFootStepRight); + VRIKUtils.CalculateInitialFootsteps(avatarVRIK, out _vrikInitialFootPosLeft, out _vrikInitialFootPosRight, out _vrikInitialFootRotLeft, out _vrikInitialFootRotRight); // Setup HeadIKTarget VRIKUtils.SetupHeadIKTarget(avatarVRIK); @@ -643,4 +667,4 @@ internal class DesktopVRIKSystem : MonoBehaviour muscles[(int)index] = value; } } -} +} \ No newline at end of file diff --git a/DesktopVRIK/Integrations/BTKUIAddon.cs b/DesktopVRIK/Integrations/BTKUIAddon.cs index 62387c5..5c25427 100644 --- a/DesktopVRIK/Integrations/BTKUIAddon.cs +++ b/DesktopVRIK/Integrations/BTKUIAddon.cs @@ -17,21 +17,20 @@ public static class BTKUIAddon AddMelonToggle(ref miscCategory, DesktopVRIKMod.EntryEnabled); //Add my own page to not clog up Misc Menu - Page desktopVRIKPage = miscCategory.AddPage("DesktopVRIK Settings", "", "Configure the settings for DesktopVRIK.", "DesktopVRIK"); desktopVRIKPage.MenuTitle = "DesktopVRIK Settings"; - Category desktopVRIKCategory = desktopVRIKPage.AddCategory(DesktopVRIKMod.SettingsCategory); - + // General Settings - //AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryEnabled); AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryPlantFeet); - AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryResetFootstepsOnIdle); - + // Calibration Settings AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryUseVRIKToes); AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryFindUnmappedToes); - + + // Fine-tuning Settings + AddMelonToggle(ref desktopVRIKCategory, DesktopVRIKMod.EntryResetFootstepsOnIdle); + // Body Leaning Weight AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryBodyLeanWeight, 0, 1f, 1); @@ -39,7 +38,11 @@ public static class BTKUIAddon AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryBodyHeadingLimit, 0, 90f, 0); AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryPelvisHeadingWeight, 0, 1f, 1); AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryChestHeadingWeight, 0, 1f, 1); + + // Lerp Speed + AddMelonSlider(ref desktopVRIKPage, DesktopVRIKMod.EntryIKLerpSpeed, 0, 20f, 0); } + private static void AddMelonToggle(ref Category category, MelonLoader.MelonPreferences_Entry entry) { category.AddToggle(entry.DisplayName, entry.Description, entry.Value).OnValueUpdated += b => entry.Value = b; diff --git a/DesktopVRIK/Main.cs b/DesktopVRIK/Main.cs index 109bf76..09cfcea 100644 --- a/DesktopVRIK/Main.cs +++ b/DesktopVRIK/Main.cs @@ -15,12 +15,12 @@ public class DesktopVRIKMod : MelonMod public static readonly MelonPreferences_Entry EntryPlantFeet = CategoryDesktopVRIK.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."); + 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."); - public static readonly MelonPreferences_Entry EntryResetFootstepsOnIdle = - CategoryDesktopVRIK.CreateEntry("Reset Footsteps on Idle", false, description: "Forces Locomotion Footsteps to reset to their initial position on return to idle. This is a bit aggressive."); - public static readonly MelonPreferences_Entry EntryFindUnmappedToes = CategoryDesktopVRIK.CreateEntry("Find Unmapped Toes", false, description: "Determines if DesktopVRIK should look for unmapped toe bones if the humanoid rig does not have any."); @@ -36,6 +36,14 @@ public class DesktopVRIKMod : MelonMod 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."); + 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."); + + public static readonly MelonPreferences_Entry EntryIntegrationAMT = + CategoryDesktopVRIK.CreateEntry("AMT Integration", true, description: "Relies on AvatarMotionTweaker to handle VRIK Locomotion weights if available."); + + public static bool integration_AMT = false; + public override void OnInitializeMelon() { Logger = LoggerInstance; @@ -50,6 +58,16 @@ public class DesktopVRIKMod : MelonMod Logger.Msg("Initializing BTKUILib support."); 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; + } + else + { + Logger.Msg("AvatarMotionTweaker was not found. Using built-in VRIK locomotion handling."); + } } internal static void UpdateAllSettings() @@ -64,10 +82,18 @@ public class DesktopVRIKMod : MelonMod 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; DesktopVRIKSystem.Instance.Setting_FindUnmappedToes = EntryFindUnmappedToes.Value; + + // Fine-tuning Settings + DesktopVRIKSystem.Instance.Setting_ResetFootsteps = EntryResetFootstepsOnIdle.Value; + + // Integration Settings + DesktopVRIKSystem.Instance.Setting_IntegrationAMT = EntryIntegrationAMT.Value && integration_AMT; } void OnUpdateSettings(object arg1, object arg2) => UpdateAllSettings(); diff --git a/DesktopVRIK/Properties/AssemblyInfo.cs b/DesktopVRIK/Properties/AssemblyInfo.cs index 3cd7c04..0fefe61 100644 --- a/DesktopVRIK/Properties/AssemblyInfo.cs +++ b/DesktopVRIK/Properties/AssemblyInfo.cs @@ -26,6 +26,6 @@ using System.Reflection; namespace NAK.Melons.DesktopVRIK.Properties; internal static class AssemblyInfoParams { - public const string Version = "4.1.2"; + public const string Version = "4.1.3"; public const string Author = "NotAKidoS"; } \ No newline at end of file diff --git a/DesktopVRIK/VRIKUtils.cs b/DesktopVRIK/VRIKUtils.cs index 32fedd7..21c36c3 100644 --- a/DesktopVRIK/VRIKUtils.cs +++ b/DesktopVRIK/VRIKUtils.cs @@ -154,10 +154,33 @@ public static class VRIKUtils initialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f; } - public static void CalculateInitialFootsteps(VRIK vrik, out Vector3 initialFootstepLeft, out Vector3 initialFootstepRight) + public static void CalculateInitialFootsteps(VRIK vrik, out Vector3 initialFootPosLeft, out Vector3 initialFootPosRight, out Quaternion initialFootRotLeft, out Quaternion initialFootRotRight) { - initialFootstepLeft = vrik.references.root.InverseTransformPoint(vrik.references.leftFoot.position); - initialFootstepRight = vrik.references.root.InverseTransformPoint(vrik.references.rightFoot.position); + Transform root = vrik.references.root; + Transform leftFoot = vrik.references.leftFoot; + Transform rightFoot = vrik.references.rightFoot; + + // Calculate the world rotation of the root bone at the current frame + 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; + } + + public static void SetFootsteps(VRIK vrik, Vector3 footPosLeft, Vector3 footPosRight, Quaternion footRotLeft, Quaternion footRotRight) + { + var locomotionSolver = vrik.solver.locomotion; + + var footsteps = locomotionSolver.footsteps; + var footstepLeft = footsteps[0]; + var footstepRight = footsteps[1]; + + var rootWorldRot = vrik.references.root.rotation; + footstepLeft.Reset(rootWorldRot, vrik.transform.TransformPoint(footPosLeft), rootWorldRot * footRotLeft); + footstepRight.Reset(rootWorldRot, vrik.transform.TransformPoint(footPosRight), rootWorldRot * footRotRight); } public static void SetupHeadIKTarget(VRIK vrik) diff --git a/DesktopVRIK/format.json b/DesktopVRIK/format.json index 0290432..acd5fa4 100644 --- a/DesktopVRIK/format.json +++ b/DesktopVRIK/format.json @@ -1,7 +1,7 @@ { "_id": 117, "name": "DesktopVRIK", - "modversion": "4.1.2", + "modversion": "4.1.3", "gameversion": "2022r170", "loaderversion": "0.5.7", "modtype": "Mod", @@ -17,8 +17,8 @@ "requirements": [ "BTKUILib" ], - "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.2/DesktopVRIK.dll", + "downloadlink": "https://github.com/NotAKidOnSteam/DesktopVRIK/releases/download/v4.1.3/DesktopVRIK.dll", "sourcelink": "https://github.com/NotAKidOnSteam/DesktopVRIK/", - "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem/PlayerSetup.\n\n DesktopVRIK will now handle VRIK Locomotion weight instead of relying on CVR & AMT to handle it. This means LeapMotionExtension, PickupArmMovement, and CVRLimbGrabber will now work while in crouch/prone.", + "changelog": "- No longer requires AvatarMotionTweaker.\n- No longer piggybacks on IKSystem/PlayerSetup.\n- Tweaks to Locomotion & IKSolver weight blending.\n\n DesktopVRIK will now handle VRIK Locomotion weight instead of relying on CVR & AMT to handle it. This means LeapMotionExtension, PickupArmMovement, and CVRLimbGrabber will now work while in crouch/prone.", "embedcolor": "9b59b6" } \ No newline at end of file