diff --git a/README.md b/README.md index 778515c..aa61388 100644 --- a/README.md +++ b/README.md @@ -8,5 +8,5 @@ Merged set of MelonLoader mods for ChilloutVR. | Desktop Head Tracking | ml_dht | 1.0.6 | Yes | Working | | Desktop Reticle Switch | ml_drs | 1.0.0 | Yes | Working | | Four Point Tracking | ml_fpt | 1.0.8 | Yes | Working | -| Leap Motion Extension | ml_lme | 1.2.2 | On review | Working | +| Leap Motion Extension | ml_lme | 1.2.3 | On review | Working | | Server Connection Info | ml_sci | 1.0.2 | Yes | Working | diff --git a/ml_lme/GestureMatcher.cs b/ml_lme/GestureMatcher.cs index 4f4c872..178ac99 100644 --- a/ml_lme/GestureMatcher.cs +++ b/ml_lme/GestureMatcher.cs @@ -22,6 +22,7 @@ public class GesturesData public bool[] m_handsPresenses = null; public Vector3[] m_handsPositons = null; public Quaternion[] m_handsRotations = null; + public Vector3[] m_elbowPositions = null; public float[] m_leftFingersBends = null; public float[] m_leftFingersSpreads = null; public float[] m_rightFingersBends = null; @@ -32,6 +33,7 @@ public GesturesData() m_handsPresenses = new bool[ms_handsCount]; m_handsPositons = new Vector3[ms_handsCount]; m_handsRotations = new Quaternion[ms_handsCount]; + m_elbowPositions = new Vector3[ms_handsCount]; m_leftFingersBends = new float[ms_fingersCount]; m_leftFingersSpreads = new float[ms_fingersCount]; m_rightFingersBends = new float[ms_fingersCount]; @@ -61,6 +63,7 @@ public static void GetGestures(Leap.Frame p_frame, ref GesturesData p_data) p_data.m_handsPresenses[l_sideID] = true; FillHandPosition(l_hand, ref p_data.m_handsPositons[l_sideID]); FillHandRotation(l_hand, ref p_data.m_handsRotations[l_sideID]); + FillElbowPosition(l_hand, ref p_data.m_elbowPositions[l_sideID]); switch(l_sideID) { case 0: @@ -96,6 +99,13 @@ static void FillHandRotation(Leap.Hand p_hand, ref Quaternion p_rot) p_rot.w = p_hand.Rotation.w; } + static void FillElbowPosition(Leap.Hand p_hand, ref Vector3 p_pos) + { + p_pos.x = p_hand.Arm.ElbowPosition.x; + p_pos.y = p_hand.Arm.ElbowPosition.y; + p_pos.z = p_hand.Arm.ElbowPosition.z; + } + static void FillFingerBends(Leap.Hand p_hand, ref float[] p_bends) { foreach(Leap.Finger l_finger in p_hand.Fingers) diff --git a/ml_lme/LeapIK.cs b/ml_lme/LeapIK.cs deleted file mode 100644 index 8629782..0000000 --- a/ml_lme/LeapIK.cs +++ /dev/null @@ -1,66 +0,0 @@ -using UnityEngine; - -namespace ml_lme -{ - [DisallowMultipleComponent] - class LeapIK : MonoBehaviour - { - bool m_enabled = true; - bool m_fingersOnly = false; - - Animator m_animator = null; - Transform m_leftHand = null; - Transform m_rightHand = null; - - float m_leftHandWeight = 0f; - float m_rightHandWeight = 0f; - - bool m_leftHandVisible = false; - bool m_rightHandVisible = false; - - void Start() - { - m_animator = this.GetComponent(); - } - - void OnAnimatorIK() - { - if(m_enabled && !m_fingersOnly && (m_animator != null)) - { - if(m_leftHand != null) - { - m_leftHandWeight = Mathf.Lerp(m_leftHandWeight, m_leftHandVisible ? 1f : 0f, 0.25f); - m_animator.SetIKPositionWeight(AvatarIKGoal.LeftHand, m_leftHandWeight); - m_animator.SetIKRotationWeight(AvatarIKGoal.LeftHand, m_leftHandWeight); - m_animator.SetIKPosition(AvatarIKGoal.LeftHand, m_leftHand.position); - m_animator.SetIKRotation(AvatarIKGoal.LeftHand, m_leftHand.rotation); - } - - if(m_rightHand != null) - { - m_rightHandWeight = Mathf.Lerp(m_rightHandWeight, m_rightHandVisible ? 1f : 0f, 0.25f); - m_animator.SetIKPositionWeight(AvatarIKGoal.RightHand, m_rightHandWeight); - m_animator.SetIKRotationWeight(AvatarIKGoal.RightHand, m_rightHandWeight); - m_animator.SetIKPosition(AvatarIKGoal.RightHand, m_rightHand.position); - m_animator.SetIKRotation(AvatarIKGoal.RightHand, m_rightHand.rotation); - } - } - } - - public void SetEnabled(bool p_state) => m_enabled = p_state; - - public void SetFingersOnly(bool p_state) => m_fingersOnly = p_state; - - public void SetHands(Transform p_left, Transform p_right) - { - m_leftHand = p_left; - m_rightHand = p_right; - } - - public void SetHandsVisibility(bool p_left, bool p_right) - { - m_leftHandVisible = p_left; - m_rightHandVisible = p_right; - } - } -} diff --git a/ml_lme/LeapTracked.cs b/ml_lme/LeapTracked.cs index 0a7c141..7dae46d 100644 --- a/ml_lme/LeapTracked.cs +++ b/ml_lme/LeapTracked.cs @@ -2,6 +2,7 @@ using ABI_RC.Core.Savior; using ABI_RC.Systems.IK; using RootMotion.FinalIK; +using System.Reflection; using UnityEngine; namespace ml_lme @@ -9,20 +10,28 @@ namespace ml_lme [DisallowMultipleComponent] class LeapTracked : MonoBehaviour { + static readonly float[] ms_tposeMuscles = typeof(ABI_RC.Systems.IK.SubSystems.BodySystem).GetField("TPoseMuscles", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as float[]; static readonly Quaternion ms_offsetLeft = Quaternion.Euler(0f, 0f, 270f); static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 0f, 90f); + static readonly Quaternion ms_offsetLeftDesktop = Quaternion.Euler(0f, 90f, 0f); + static readonly Quaternion ms_offsetRightDesktop = Quaternion.Euler(0f, 270f, 0f); IndexIK m_indexIK = null; VRIK m_vrIK = null; + Vector2 m_armsWeights = Vector2.zero; bool m_enabled = true; bool m_fingersOnly = false; + bool m_trackElbows = true; - LeapIK m_leapIK = null; + ArmIK m_leftIK = null; + ArmIK m_rightIK = null; Transform m_leftHand = null; Transform m_rightHand = null; Transform m_leftHandTarget = null; Transform m_rightHandTarget = null; + Transform m_leftElbow = null; + Transform m_rightElbow = null; bool m_leftTargetActive = false; bool m_rightTargetActive = false; @@ -56,8 +65,11 @@ public void SetEnabled(bool p_state) CVRInputManager.Instance.individualFingerTracking = (m_enabled || Utils.AreKnucklesInUse()); } - if(m_leapIK != null) - m_leapIK.SetEnabled(m_enabled); + if((m_leftIK != null) && (m_rightIK != null)) + { + m_leftIK.enabled = (m_enabled && !m_fingersOnly); + m_rightIK.enabled = (m_enabled && !m_fingersOnly); + } if(!m_enabled || m_fingersOnly) RestoreIK(); @@ -67,25 +79,55 @@ public void SetFingersOnly(bool p_state) { m_fingersOnly = p_state; - if(m_leapIK != null) - m_leapIK.SetFingersOnly(m_fingersOnly); + if((m_leftIK != null) && (m_rightIK != null)) + { + m_leftIK.enabled = (m_enabled && !m_fingersOnly); + m_rightIK.enabled = (m_enabled && !m_fingersOnly); + } if(!m_enabled || m_fingersOnly) RestoreIK(); } - public void SetHands(Transform p_left, Transform p_right) + public void SetTrackElbows(bool p_state) + { + m_trackElbows = p_state; + + if((m_leftIK != null) && (m_rightIK != null)) + { + m_leftIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + m_rightIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + } + + if(m_vrIK != null) + { + if(m_leftTargetActive) + m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + if(m_rightTargetActive) + m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + } + } + + public void SetTransforms(Transform p_left, Transform p_right, Transform p_leftElbow, Transform p_rightElbow) { m_leftHand = p_left; m_rightHand = p_right; + + m_leftElbow = p_leftElbow; + m_rightElbow = p_rightElbow; } public void UpdateTracking(GestureMatcher.GesturesData p_gesturesData) { if(m_enabled && (m_indexIK != null)) { - if(m_leapIK != null) - m_leapIK.SetHandsVisibility(p_gesturesData.m_handsPresenses[0], p_gesturesData.m_handsPresenses[1]); + if((m_leftIK != null) && (m_rightIK != null)) + { + m_leftIK.solver.IKPositionWeight = Mathf.Lerp(m_leftIK.solver.IKPositionWeight, (p_gesturesData.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_leftIK.solver.IKRotationWeight = Mathf.Lerp(m_leftIK.solver.IKRotationWeight, (p_gesturesData.m_handsPresenses[0] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightIK.solver.IKPositionWeight = Mathf.Lerp(m_rightIK.solver.IKPositionWeight, (p_gesturesData.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); + m_rightIK.solver.IKRotationWeight = Mathf.Lerp(m_rightIK.solver.IKPositionWeight, (p_gesturesData.m_handsPresenses[1] && !m_fingersOnly) ? 1f : 0f, 0.25f); + } if(p_gesturesData.m_handsPresenses[0]) { @@ -128,22 +170,30 @@ public void UpdateTracking(GestureMatcher.GesturesData p_gesturesData) if(p_gesturesData.m_handsPresenses[0] && !m_leftTargetActive) { m_vrIK.solver.leftArm.target = m_leftHandTarget; + m_vrIK.solver.leftArm.bendGoal = m_leftElbow; + m_vrIK.solver.leftArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_leftTargetActive = true; } if(!p_gesturesData.m_handsPresenses[0] && m_leftTargetActive) { m_vrIK.solver.leftArm.target = IKSystem.Instance.leftHandAnchor; + m_vrIK.solver.leftArm.bendGoal = null; + m_vrIK.solver.leftArm.bendGoalWeight = 0f; m_leftTargetActive = false; } if(p_gesturesData.m_handsPresenses[1] && !m_rightTargetActive) { m_vrIK.solver.rightArm.target = m_rightHandTarget; + m_vrIK.solver.rightArm.bendGoal = m_rightElbow; + m_vrIK.solver.rightArm.bendGoalWeight = (m_trackElbows ? 1f : 0f); m_rightTargetActive = true; } if(!p_gesturesData.m_handsPresenses[1] && m_rightTargetActive) { m_vrIK.solver.rightArm.target = IKSystem.Instance.rightHandAnchor; + m_vrIK.solver.rightArm.bendGoal = null; + m_vrIK.solver.rightArm.bendGoalWeight = 0f; m_rightTargetActive = false; } } @@ -152,8 +202,9 @@ public void UpdateTracking(GestureMatcher.GesturesData p_gesturesData) public void OnAvatarClear() { - m_leapIK = null; m_vrIK = null; + m_leftIK = null; + m_rightIK = null; m_leftTargetActive = false; m_rightTargetActive = false; @@ -161,6 +212,8 @@ public void OnAvatarClear() m_leftHandTarget.localRotation = Quaternion.identity; m_rightHandTarget.localPosition = Vector3.zero; m_rightHandTarget.localRotation = Quaternion.identity; + + m_armsWeights.Set(0f, 0f); } public void OnCalibrateAvatar() @@ -176,24 +229,107 @@ public void OnCalibrateAvatar() if(PlayerSetup.Instance._animator.isHuman) { + HumanPoseHandler l_poseHandler = null; + HumanPose l_initPose = new HumanPose(); + + // Force desktop non-VRIK avatar into T-Pose + if(m_vrIK == null) + { + l_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._avatar.transform); + l_poseHandler.GetHumanPose(ref l_initPose); + + HumanPose l_tPose = new HumanPose(); + l_tPose.bodyPosition = l_initPose.bodyPosition; + l_tPose.bodyRotation = l_initPose.bodyRotation; + l_tPose.muscles = new float[l_initPose.muscles.Length]; + for(int i = 0; i < l_tPose.muscles.Length; i++) + l_tPose.muscles[i] = ms_tposeMuscles[i]; + + l_poseHandler.SetHumanPose(ref l_tPose); + } + Transform l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand); if(l_hand != null) - m_leftHandTarget.localRotation = ms_offsetLeft * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation; + m_leftHandTarget.localRotation = ((m_vrIK != null) ? ms_offsetLeft : ms_offsetLeftDesktop) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation; l_hand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand); if(l_hand != null) - m_rightHandTarget.localRotation = ms_offsetRight * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation; + m_rightHandTarget.localRotation = ((m_vrIK != null) ? ms_offsetRight : ms_offsetRightDesktop) * (PlayerSetup.Instance._avatar.transform.GetMatrix().inverse * l_hand.GetMatrix()).rotation; if(m_vrIK == null) { - m_leapIK = PlayerSetup.Instance._animator.gameObject.AddComponent(); - m_leapIK.SetHands(m_leftHand, m_rightHand); - m_leapIK.SetEnabled(m_enabled); - m_leapIK.SetFingersOnly(m_fingersOnly); + Transform l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.UpperChest); + if(l_chest == null) + l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Chest); + if(l_chest == null) + l_chest = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Spine); + + m_leftIK = PlayerSetup.Instance._avatar.AddComponent(); + m_leftIK.solver.isLeft = true; + m_leftIK.solver.SetChain( + l_chest, + PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftShoulder), + PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftUpperArm), + PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftLowerArm), + PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand), + PlayerSetup.Instance._animator.transform + ); + m_leftIK.solver.arm.target = m_leftHandTarget; + m_leftIK.solver.arm.bendGoal = m_leftElbow; + m_leftIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + m_leftIK.enabled = (m_enabled && !m_fingersOnly); + + m_rightIK = PlayerSetup.Instance._avatar.AddComponent(); + m_rightIK.solver.isLeft = false; + m_rightIK.solver.SetChain( + l_chest, + PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightShoulder), + PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightUpperArm), + PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightLowerArm), + PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand), + PlayerSetup.Instance._animator.transform + ); + m_rightIK.solver.arm.target = m_rightHandTarget; + m_rightIK.solver.arm.bendGoal = m_rightElbow; + m_rightIK.solver.arm.bendGoalWeight = (m_trackElbows ? 1f : 0f); + m_rightIK.enabled = (m_enabled && !m_fingersOnly); + + l_poseHandler.SetHumanPose(ref l_initPose); } + else + { + m_vrIK.onPreSolverUpdate.AddListener(this.OnIKPreUpdate); + m_vrIK.onPostSolverUpdate.AddListener(this.OnIKPostUpdate); + } + + l_poseHandler?.Dispose(); } } + void OnIKPreUpdate() + { + m_armsWeights.Set(m_vrIK.solver.leftArm.positionWeight, m_vrIK.solver.rightArm.positionWeight); + + if(m_leftTargetActive && Mathf.Approximately(m_armsWeights.x, 0f)) + { + m_vrIK.solver.leftArm.positionWeight = 1f; + m_vrIK.solver.leftArm.rotationWeight = 1f; + } + if(m_rightTargetActive && Mathf.Approximately(m_armsWeights.y, 0f)) + { + m_vrIK.solver.rightArm.positionWeight = 1f; + m_vrIK.solver.rightArm.rotationWeight = 1f; + } + } + void OnIKPostUpdate() + { + m_vrIK.solver.leftArm.positionWeight = m_armsWeights.x; + m_vrIK.solver.leftArm.rotationWeight = m_armsWeights.x; + + m_vrIK.solver.rightArm.positionWeight = m_armsWeights.y; + m_vrIK.solver.rightArm.rotationWeight = m_armsWeights.y; + } + void RestoreIK() { if(m_vrIK != null) @@ -201,11 +337,15 @@ void RestoreIK() if(m_leftTargetActive) { m_vrIK.solver.leftArm.target = IKSystem.Instance.leftHandAnchor; + m_vrIK.solver.leftArm.bendGoal = null; + m_vrIK.solver.leftArm.bendGoalWeight = 0f; m_leftTargetActive = false; } if(m_rightTargetActive) { m_vrIK.solver.rightArm.target = IKSystem.Instance.rightHandAnchor; + m_vrIK.solver.rightArm.bendGoal = null; + m_vrIK.solver.rightArm.bendGoalWeight = 0f; m_rightTargetActive = false; } } diff --git a/ml_lme/Main.cs b/ml_lme/Main.cs index 74ea989..70fdcc0 100644 --- a/ml_lme/Main.cs +++ b/ml_lme/Main.cs @@ -1,7 +1,7 @@ using ABI_RC.Core.Player; using ABI_RC.Core.UI; -using UnityEngine; using System.Reflection; +using UnityEngine; namespace ml_lme { @@ -18,6 +18,7 @@ public class LeapMotionExtension : MelonLoader.MelonMod GameObject m_leapTrackingRoot = null; GameObject[] m_leapHands = null; + GameObject[] m_leapElbows = null; GameObject m_leapControllerModel = null; LeapTracked m_leapTracked = null; @@ -29,14 +30,15 @@ public override void OnInitializeMelon() DependenciesHandler.ExtractDependencies(); Settings.Init(); - Settings.EnabledChange += this.OnSettingsEnableChange; - Settings.DesktopOffsetChange += this.OnSettingsDesktopOffsetChange; - Settings.FingersOnlyChange += this.OnSettingsFingersOptionChange; - Settings.ModelVisibilityChange += this.OnSettingsModelVisibilityChange; - Settings.TrackingModeChange += this.OnSettingsTrackingModeChange; - Settings.RootAngleChange += this.OnSettingsRootAngleChange; - Settings.HeadAttachChange += this.OnSettingsHeadAttachChange; - Settings.HeadOffsetChange += this.OnSettingsHeadOffsetChange; + Settings.EnabledChange += this.OnEnableChange; + Settings.DesktopOffsetChange += this.OnDesktopOffsetChange; + Settings.FingersOnlyChange += this.OnFingersOptionChange; + Settings.ModelVisibilityChange += this.OnModelVisibilityChange; + Settings.TrackingModeChange += this.OnTrackingModeChange; + Settings.RootAngleChange += this.OnRootAngleChange; + Settings.HeadAttachChange += this.OnHeadAttachChange; + Settings.HeadOffsetChange += this.OnHeadOffsetChange; + Settings.TrackElbowsChange += this.OnTrackElbowsChange; m_leapController = new Leap.Controller(); m_leapController.Device += this.OnLeapDeviceInitialized; @@ -47,6 +49,7 @@ public override void OnInitializeMelon() m_gesturesData = new GestureMatcher.GesturesData(); m_leapHands = new GameObject[GestureMatcher.GesturesData.ms_handsCount]; + m_leapElbows = new GameObject[GestureMatcher.GesturesData.ms_handsCount]; // Patches HarmonyInstance.Patch( @@ -87,6 +90,11 @@ System.Collections.IEnumerator CreateTrackingObjects() m_leapHands[i].transform.parent = m_leapTrackingRoot.transform; m_leapHands[i].transform.localPosition = Vector3.zero; m_leapHands[i].transform.localRotation = Quaternion.identity; + + m_leapElbows[i] = new GameObject("LeapElbow" + i); + m_leapElbows[i].transform.parent = m_leapTrackingRoot.transform; + m_leapElbows[i].transform.localPosition = Vector3.zero; + m_leapElbows[i].transform.localRotation = Quaternion.identity; } m_leapControllerModel = AssetsHandler.GetAsset("assets/models/leapmotion/leap_motion_1_0.obj"); @@ -100,13 +108,14 @@ System.Collections.IEnumerator CreateTrackingObjects() // Player setup m_leapTracked = PlayerSetup.Instance.gameObject.AddComponent(); - m_leapTracked.SetHands(m_leapHands[0].transform, m_leapHands[1].transform); - - OnSettingsEnableChange(Settings.Enabled); - OnSettingsFingersOptionChange(Settings.FingersOnly); - OnSettingsModelVisibilityChange(Settings.ModelVisibility); - OnSettingsTrackingModeChange(Settings.TrackingMode); - OnSettingsHeadAttachChange(Settings.HeadAttach); // Includes offsets and parenting + m_leapTracked.SetTransforms(m_leapHands[0].transform, m_leapHands[1].transform, m_leapElbows[0].transform, m_leapElbows[1].transform); + m_leapTracked.SetTrackElbows(Settings.TrackElbows); + + OnEnableChange(Settings.Enabled); + OnFingersOptionChange(Settings.FingersOnly); + OnModelVisibilityChange(Settings.ModelVisibility); + OnTrackingModeChange(Settings.TrackingMode); + OnHeadAttachChange(Settings.HeadAttach); // Includes offsets and parenting } public override void OnUpdate() @@ -132,6 +141,10 @@ public override void OnUpdate() ReorientateLeapToUnity(ref l_pos, ref l_rot, Settings.TrackingMode); m_leapHands[i].transform.localPosition = l_pos; m_leapHands[i].transform.localRotation = l_rot; + + l_pos = m_gesturesData.m_elbowPositions[i]; + ReorientateLeapToUnity(ref l_pos, ref l_rot, Settings.TrackingMode); + m_leapElbows[i].transform.localPosition = l_pos; } } } @@ -143,7 +156,7 @@ public override void OnUpdate() } // Settings changes - void OnSettingsEnableChange(bool p_state) + void OnEnableChange(bool p_state) { if(p_state) { @@ -157,7 +170,7 @@ void OnSettingsEnableChange(bool p_state) m_leapTracked.SetEnabled(p_state); } - void OnSettingsDesktopOffsetChange(Vector3 p_offset) + void OnDesktopOffsetChange(Vector3 p_offset) { if((m_leapTrackingRoot != null) && !Settings.HeadAttach) { @@ -168,19 +181,19 @@ void OnSettingsDesktopOffsetChange(Vector3 p_offset) } } - void OnSettingsFingersOptionChange(bool p_state) + void OnFingersOptionChange(bool p_state) { if(m_leapTracked != null) m_leapTracked.SetFingersOnly(p_state); } - void OnSettingsModelVisibilityChange(bool p_state) + void OnModelVisibilityChange(bool p_state) { if(m_leapControllerModel != null) m_leapControllerModel.SetActive(p_state); } - void OnSettingsTrackingModeChange(Settings.LeapTrackingMode p_mode) + void OnTrackingModeChange(Settings.LeapTrackingMode p_mode) { if(Settings.Enabled) UpdateDeviceTrackingMode(); @@ -202,13 +215,13 @@ void OnSettingsTrackingModeChange(Settings.LeapTrackingMode p_mode) } } - void OnSettingsRootAngleChange(float p_angle) + void OnRootAngleChange(float p_angle) { if(m_leapTrackingRoot != null) m_leapTrackingRoot.transform.localRotation = Quaternion.Euler(p_angle, 0f, 0f); } - void OnSettingsHeadAttachChange(bool p_state) + void OnHeadAttachChange(bool p_state) { if(m_leapTrackingRoot != null) { @@ -247,7 +260,7 @@ void OnSettingsHeadAttachChange(bool p_state) } } - void OnSettingsHeadOffsetChange(Vector3 p_offset) + void OnHeadOffsetChange(Vector3 p_offset) { if((m_leapTrackingRoot != null) && Settings.HeadAttach) { @@ -257,6 +270,12 @@ void OnSettingsHeadOffsetChange(Vector3 p_offset) m_leapTrackingRoot.transform.localPosition = p_offset; } } + + void OnTrackElbowsChange(bool p_state) + { + if(m_leapTracked != null) + m_leapTracked.SetTrackElbows(p_state); + } // Internal utility void UpdateDeviceTrackingMode() @@ -328,8 +347,7 @@ void OnAvatarClear() MelonLoader.MelonLogger.Error(e); } } - - // Sneaky forced IndexIK calibration + static void OnCalibrateAvatar_Postfix() => ms_instance?.OnCalibrateAvatar(); void OnCalibrateAvatar() { @@ -338,7 +356,7 @@ void OnCalibrateAvatar() if(m_leapTracked != null) m_leapTracked.OnCalibrateAvatar(); - OnSettingsHeadAttachChange(Settings.HeadAttach); + OnHeadAttachChange(Settings.HeadAttach); } catch(System.Exception e) { diff --git a/ml_lme/Properties/AssemblyInfo.cs b/ml_lme/Properties/AssemblyInfo.cs index 1db9b58..3ec803a 100644 --- a/ml_lme/Properties/AssemblyInfo.cs +++ b/ml_lme/Properties/AssemblyInfo.cs @@ -1,10 +1,10 @@ using System.Reflection; [assembly: AssemblyTitle("LeapMotionExtension")] -[assembly: AssemblyVersion("1.2.2")] -[assembly: AssemblyFileVersion("1.2.2")] +[assembly: AssemblyVersion("1.2.3")] +[assembly: AssemblyFileVersion("1.2.3")] -[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.2.2", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] +[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.2.3", "SDraw", "https://github.com/SDraw/ml_mods_cvr")] [assembly: MelonLoader.MelonGame(null, "ChilloutVR")] [assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)] [assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)] diff --git a/ml_lme/README.md b/ml_lme/README.md index 652700e..310543c 100644 --- a/ml_lme/README.md +++ b/ml_lme/README.md @@ -18,5 +18,6 @@ Available mod's settings in `Settings - Implementation - Leap Motion Tracking`: * **Attach to head:** attach hands transformation to head instead of body, disabled by default. * **Head offset X/Y/Z:** offset position for head attachment (`Attach to head` is **`true`**), (0, -30, 15) by default. * **Offset angle:** rotation around X axis, useful for neck mounts, 0 by default. +* **Track elbows:** elbows tracking, works best in `Screentop` and `HMD` tracking modes, `true` by default. * **Fingers tracking only:** apply only fingers tracking, disabled by default. * **Model visibility:** show Leap Motion controller model, useful for tracking visualizing, disabled by default. diff --git a/ml_lme/Settings.cs b/ml_lme/Settings.cs index d5c291b..29c98c3 100644 --- a/ml_lme/Settings.cs +++ b/ml_lme/Settings.cs @@ -28,7 +28,8 @@ enum ModSetting Head, HeadX, HeadY, - HeadZ + HeadZ, + TrackElbows }; static bool ms_enabled = false; @@ -39,6 +40,7 @@ enum ModSetting static float ms_rootAngle = 0f; static bool ms_headAttach = false; static Vector3 ms_headOffset = new Vector3(0f, -0.3f, 0.15f); + static bool ms_trackElbows = true; static MelonLoader.MelonPreferences_Category ms_category = null; static List ms_entries = null; @@ -51,6 +53,7 @@ enum ModSetting static public event Action RootAngleChange; static public event Action HeadAttachChange; static public event Action HeadOffsetChange; + static public event Action TrackElbowsChange; public static void Init() { @@ -69,6 +72,7 @@ public static void Init() ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadX.ToString(), 0)); ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadY.ToString(), -30)); ms_entries.Add(ms_category.CreateEntry(ModSetting.HeadZ.ToString(), 15)); + ms_entries.Add(ms_category.CreateEntry(ModSetting.TrackElbows.ToString(), true)); Load(); @@ -116,6 +120,7 @@ static void Load() (int)ms_entries[(int)ModSetting.HeadY].BoxedValue, (int)ms_entries[(int)ModSetting.HeadZ].BoxedValue ) * 0.01f; + ms_trackElbows = (bool)ms_entries[(int)ModSetting.TrackElbows].BoxedValue; } static void OnToggleUpdate(string p_name, string p_value) @@ -151,6 +156,12 @@ static void OnToggleUpdate(string p_name, string p_value) HeadAttachChange?.Invoke(ms_headAttach); } break; + + case ModSetting.TrackElbows: + { + ms_trackElbows = bool.Parse(p_value); + TrackElbowsChange?.Invoke(ms_trackElbows); + } break; } ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value); @@ -235,40 +246,37 @@ public static bool Enabled { get => ms_enabled; } - public static Vector3 DesktopOffset { get => ms_desktopOffset; } - public static bool FingersOnly { get => ms_fingersOnly; } - public static bool ModelVisibility { get => ms_modelVisibility; } - public static LeapTrackingMode TrackingMode { get => ms_trackingMode; } - public static float RootAngle { get => ms_rootAngle; } - public static bool HeadAttach { get => ms_headAttach; } - public static Vector3 HeadOffset { get => ms_headOffset; } + public static bool TrackElbows + { + get => ms_trackElbows; + } } } diff --git a/ml_lme/Utils.cs b/ml_lme/Utils.cs index 60897e0..ef789c2 100644 --- a/ml_lme/Utils.cs +++ b/ml_lme/Utils.cs @@ -10,7 +10,7 @@ static class Utils public static Matrix4x4 GetMatrix(this Transform p_transform, bool p_pos = true, bool p_rot = true, bool p_scl = false) { - return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.localScale : Vector3.one); + return Matrix4x4.TRS(p_pos ? p_transform.position : Vector3.zero, p_rot ? p_transform.rotation : Quaternion.identity, p_scl ? p_transform.lossyScale : Vector3.one); } public static void Swap(ref T lhs, ref T rhs) diff --git a/ml_lme/ml_lme.csproj b/ml_lme/ml_lme.csproj index a32cd22..8094eec 100644 --- a/ml_lme/ml_lme.csproj +++ b/ml_lme/ml_lme.csproj @@ -84,7 +84,6 @@ - diff --git a/ml_lme/resources/menu.js b/ml_lme/resources/menu.js index 210277c..a0f512d 100644 --- a/ml_lme/resources/menu.js +++ b/ml_lme/resources/menu.js @@ -350,6 +350,13 @@ function inp_dropdown_mod_lme(_obj, _callbackName) { +
+
Track elbows:
+
+
+
+
+
Fingers tracking only: