mirror of
https://github.com/hanetzer/sdraw_mods_cvr.git
synced 2025-09-03 10:29:22 +00:00
Improved fingers binding
Mechanim filtering
This commit is contained in:
parent
5bec2fcdb1
commit
00c92e1913
19 changed files with 557 additions and 239 deletions
20
README.md
20
README.md
|
@ -3,16 +3,16 @@ Merged set of MelonLoader mods for ChilloutVR.
|
||||||
**Table for game build 2023r173:**
|
**Table for game build 2023r173:**
|
||||||
| Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) |
|
| Full name | Short name | Latest version | Available in [CVRMA](https://github.com/knah/CVRMelonAssistant) |
|
||||||
|:---------:|:----------:|:--------------:| :----------------------------------------------------------------|
|
|:---------:|:----------:|:--------------:| :----------------------------------------------------------------|
|
||||||
| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.3.7 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| ✔ Yes |
|
| [Avatar Motion Tweaker](/ml_amt/README.md) | ml_amt | 1.3.7 [:arrow_down:](../../releases/latest/download/ml_amt.dll)| Yes |
|
||||||
| [Avatar Synced Look](/ml_asl/README.md) | ml_asl | 1.0.1 [:arrow_down:](../../releases/latest/download/ml_asl.dll)| ✔ Yes |
|
| [Avatar Synced Look](/ml_asl/README.md) | ml_asl | 1.0.1 [:arrow_down:](../../releases/latest/download/ml_asl.dll)| Yes |
|
||||||
| [Better Fingers Tracking](/ml_bft/README.md) | ml_bft | 1.0.0 [:arrow_down:](../../releases/latest/download/ml_bft.dll)| On review |
|
| [Better Fingers Tracking](/ml_bft/README.md) | ml_bft | 1.0.0 [:arrow_down:](../../releases/latest/download/ml_bft.dll)| Yes<br>Update review |
|
||||||
| [Desktop Head Tracking](/ml_dht/README.md) | ml_dht | 1.2.1 [:arrow_down:](../../releases/latest/download/ml_dht.dll) | ✔ Yes |
|
| [Desktop Head Tracking](/ml_dht/README.md) | ml_dht | 1.2.1 [:arrow_down:](../../releases/latest/download/ml_dht.dll) | Yes |
|
||||||
| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.6 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| ✔ Yes |
|
| [Leap Motion Extension](/ml_lme/README.md)| ml_lme | 1.4.7 [:arrow_down:](../../releases/latest/download/ml_lme.dll)| Yes<br>Update review |
|
||||||
| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.1.0 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| ✔ Yes |
|
| [Pickup Arm Movement](/ml_pam/README.md)| ml_pam | 1.1.0 [:arrow_down:](../../releases/latest/download/ml_pam.dll)| Yes |
|
||||||
| [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.5 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| ✔ Yes |
|
| [Player Movement Copycat](/ml_pmc/README.md)| ml_pmc | 1.0.5 [:arrow_down:](../../releases/latest/download/ml_pmc.dll)| Yes |
|
||||||
| [Player Ragdoll Mod](/ml_prm/README.md) | ml_prm | 1.1.3 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| ✔ Yes |
|
| [Player Ragdoll Mod](/ml_prm/README.md) | ml_prm | 1.1.3 [:arrow_down:](../../releases/latest/download/ml_prm.dll)| Yes |
|
||||||
| [Players Instance Notifier](/ml_pin/README.md) | ml_pin | 1.0.2 [:arrow_down:](../../releases/latest/download/ml_ml_pin.dll)| ✔ Yes |
|
| [Players Instance Notifier](/ml_pin/README.md) | ml_pin | 1.0.2 [:arrow_down:](../../releases/latest/download/ml_ml_pin.dll)| Yes |
|
||||||
| [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.1 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| ✔ Yes |
|
| [Vive Extended Input](/ml_vei/README.md) | ml_vei | 1.0.1 [:arrow_down:](../../releases/latest/download/ml_vei.dll)| Yes |
|
||||||
|
|
||||||
**Archived mods:**
|
**Archived mods:**
|
||||||
| Full name | Short name | Notes |
|
| Full name | Short name | Notes |
|
||||||
|
|
|
@ -9,14 +9,27 @@ namespace ml_bft
|
||||||
{
|
{
|
||||||
class FingerSystem
|
class FingerSystem
|
||||||
{
|
{
|
||||||
|
enum PlaneType
|
||||||
|
{
|
||||||
|
OXZ,
|
||||||
|
OYX
|
||||||
|
}
|
||||||
|
|
||||||
struct RotationOffset
|
struct RotationOffset
|
||||||
{
|
{
|
||||||
public Transform m_target;
|
public Transform m_target;
|
||||||
public Transform m_source;
|
public Transform m_source;
|
||||||
public Quaternion m_offset;
|
public Quaternion m_offset;
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
m_source = null;
|
||||||
|
m_target = null;
|
||||||
|
m_offset = Quaternion.identity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static readonly List<HumanBodyBones> ms_leftFingerBones = new List<HumanBodyBones>()
|
static readonly HumanBodyBones[] ms_leftFingerBones =
|
||||||
{
|
{
|
||||||
HumanBodyBones.LeftThumbProximal, HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,
|
HumanBodyBones.LeftThumbProximal, HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,
|
||||||
HumanBodyBones.LeftIndexProximal, HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,
|
HumanBodyBones.LeftIndexProximal, HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,
|
||||||
|
@ -24,7 +37,7 @@ namespace ml_bft
|
||||||
HumanBodyBones.LeftRingProximal, HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,
|
HumanBodyBones.LeftRingProximal, HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,
|
||||||
HumanBodyBones.LeftLittleProximal, HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal
|
HumanBodyBones.LeftLittleProximal, HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal
|
||||||
};
|
};
|
||||||
static readonly List<HumanBodyBones> ms_rightFingerBones = new List<HumanBodyBones>()
|
static readonly HumanBodyBones[] ms_rightFingerBones =
|
||||||
{
|
{
|
||||||
HumanBodyBones.RightThumbProximal, HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,
|
HumanBodyBones.RightThumbProximal, HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,
|
||||||
HumanBodyBones.RightIndexProximal, HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,
|
HumanBodyBones.RightIndexProximal, HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,
|
||||||
|
@ -32,6 +45,19 @@ namespace ml_bft
|
||||||
HumanBodyBones.RightRingProximal, HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,
|
HumanBodyBones.RightRingProximal, HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,
|
||||||
HumanBodyBones.RightLittleProximal, HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal
|
HumanBodyBones.RightLittleProximal, HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal
|
||||||
};
|
};
|
||||||
|
static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_rotationFixChains =
|
||||||
|
{
|
||||||
|
(HumanBodyBones.LeftThumbProximal,HumanBodyBones.LeftThumbIntermediate,true), (HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,true),
|
||||||
|
(HumanBodyBones.LeftIndexProximal,HumanBodyBones.LeftIndexIntermediate,true), (HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,true),
|
||||||
|
(HumanBodyBones.LeftMiddleProximal,HumanBodyBones.LeftMiddleIntermediate,true), (HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,true),
|
||||||
|
(HumanBodyBones.LeftRingProximal,HumanBodyBones.LeftRingIntermediate,true), (HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,true),
|
||||||
|
(HumanBodyBones.LeftLittleProximal,HumanBodyBones.LeftLittleIntermediate,true), (HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal,true),
|
||||||
|
(HumanBodyBones.RightThumbProximal,HumanBodyBones.RightThumbIntermediate,false), (HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,false),
|
||||||
|
(HumanBodyBones.RightIndexProximal,HumanBodyBones.RightIndexIntermediate,false), (HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,false),
|
||||||
|
(HumanBodyBones.RightMiddleProximal,HumanBodyBones.RightMiddleIntermediate,false), (HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal,false),
|
||||||
|
(HumanBodyBones.RightRingProximal,HumanBodyBones.RightRingIntermediate,false), (HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,false),
|
||||||
|
(HumanBodyBones.RightLittleProximal,HumanBodyBones.RightLittleIntermediate,false), (HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal,false)
|
||||||
|
};
|
||||||
|
|
||||||
public static FingerSystem Instance { get; private set; } = null;
|
public static FingerSystem Instance { get; private set; } = null;
|
||||||
|
|
||||||
|
@ -71,22 +97,43 @@ namespace ml_bft
|
||||||
if(PlayerSetup.Instance._animator.isHuman)
|
if(PlayerSetup.Instance._animator.isHuman)
|
||||||
{
|
{
|
||||||
Utils.SetAvatarTPose();
|
Utils.SetAvatarTPose();
|
||||||
InputHandler.Instance?.Rebind(PlayerSetup.Instance.transform.rotation);
|
InputHandler.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
|
||||||
|
|
||||||
|
// Try to "fix" rotations of fingers
|
||||||
|
foreach(var l_tuple in ms_rotationFixChains)
|
||||||
|
{
|
||||||
|
ReorientateTowards(
|
||||||
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
||||||
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
||||||
|
InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3),
|
||||||
|
InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3),
|
||||||
|
PlaneType.OXZ
|
||||||
|
);
|
||||||
|
ReorientateTowards(
|
||||||
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
||||||
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
||||||
|
InputHandler.Instance.GetSourceForBone(l_tuple.Item1, l_tuple.Item3),
|
||||||
|
InputHandler.Instance.GetSourceForBone(l_tuple.Item2, l_tuple.Item3),
|
||||||
|
PlaneType.OYX
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind hands
|
||||||
m_leftHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
m_leftHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||||
m_leftHandOffset.m_target = InputHandler.Instance?.GetSourceForBone(HumanBodyBones.LeftHand, true);
|
m_leftHandOffset.m_target = InputHandler.Instance.GetSourceForBone(HumanBodyBones.LeftHand, true);
|
||||||
if((m_leftHandOffset.m_source != null) && (m_leftHandOffset.m_target != null))
|
if((m_leftHandOffset.m_source != null) && (m_leftHandOffset.m_target != null))
|
||||||
m_leftHandOffset.m_offset = Quaternion.Inverse(m_leftHandOffset.m_source.rotation) * m_leftHandOffset.m_target.rotation;
|
m_leftHandOffset.m_offset = Quaternion.Inverse(m_leftHandOffset.m_source.rotation) * m_leftHandOffset.m_target.rotation;
|
||||||
|
|
||||||
m_rightHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
|
m_rightHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||||
m_rightHandOffset.m_target = InputHandler.Instance?.GetSourceForBone(HumanBodyBones.RightHand, false);
|
m_rightHandOffset.m_target = InputHandler.Instance.GetSourceForBone(HumanBodyBones.RightHand, false);
|
||||||
if((m_rightHandOffset.m_source != null) && (m_rightHandOffset.m_target != null))
|
if((m_rightHandOffset.m_source != null) && (m_rightHandOffset.m_target != null))
|
||||||
m_rightHandOffset.m_offset = Quaternion.Inverse(m_rightHandOffset.m_source.rotation) * m_rightHandOffset.m_target.rotation;
|
m_rightHandOffset.m_offset = Quaternion.Inverse(m_rightHandOffset.m_source.rotation) * m_rightHandOffset.m_target.rotation;
|
||||||
|
|
||||||
|
// Bind fingers
|
||||||
foreach(HumanBodyBones p_bone in ms_leftFingerBones)
|
foreach(HumanBodyBones p_bone in ms_leftFingerBones)
|
||||||
{
|
{
|
||||||
Transform l_avatarBone = PlayerSetup.Instance._animator.GetBoneTransform(p_bone);
|
Transform l_avatarBone = PlayerSetup.Instance._animator.GetBoneTransform(p_bone);
|
||||||
Transform l_controllerBone = InputHandler.Instance?.GetSourceForBone(p_bone, true);
|
Transform l_controllerBone = InputHandler.Instance.GetSourceForBone(p_bone, true);
|
||||||
if((l_avatarBone != null) && (l_controllerBone != null))
|
if((l_avatarBone != null) && (l_controllerBone != null))
|
||||||
{
|
{
|
||||||
RotationOffset l_offset = new RotationOffset();
|
RotationOffset l_offset = new RotationOffset();
|
||||||
|
@ -96,11 +143,10 @@ namespace ml_bft
|
||||||
m_leftFingerOffsets.Add(l_offset);
|
m_leftFingerOffsets.Add(l_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach(HumanBodyBones p_bone in ms_rightFingerBones)
|
foreach(HumanBodyBones p_bone in ms_rightFingerBones)
|
||||||
{
|
{
|
||||||
Transform l_avatarBone = PlayerSetup.Instance._animator.GetBoneTransform(p_bone);
|
Transform l_avatarBone = PlayerSetup.Instance._animator.GetBoneTransform(p_bone);
|
||||||
Transform l_controllerBone = InputHandler.Instance?.GetSourceForBone(p_bone, false);
|
Transform l_controllerBone = InputHandler.Instance.GetSourceForBone(p_bone, false);
|
||||||
if((l_avatarBone != null) && (l_controllerBone != null))
|
if((l_avatarBone != null) && (l_controllerBone != null))
|
||||||
{
|
{
|
||||||
RotationOffset l_offset = new RotationOffset();
|
RotationOffset l_offset = new RotationOffset();
|
||||||
|
@ -119,6 +165,10 @@ namespace ml_bft
|
||||||
{
|
{
|
||||||
m_ready = false;
|
m_ready = false;
|
||||||
m_pose = new HumanPose();
|
m_pose = new HumanPose();
|
||||||
|
|
||||||
|
m_leftHandOffset.Reset();
|
||||||
|
m_rightHandOffset.Reset();
|
||||||
|
|
||||||
m_leftFingerOffsets.Clear();
|
m_leftFingerOffsets.Clear();
|
||||||
m_rightFingerOffsets.Clear();
|
m_rightFingerOffsets.Clear();
|
||||||
}
|
}
|
||||||
|
@ -199,5 +249,49 @@ namespace ml_bft
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReorientateTowards(Transform p_target, Transform p_targetEnd, Transform p_source, Transform p_sourceEnd, PlaneType p_plane)
|
||||||
|
{
|
||||||
|
if((p_target != null) && (p_targetEnd != null) && (p_source != null) && (p_sourceEnd != null))
|
||||||
|
{
|
||||||
|
Quaternion l_playerInv = Quaternion.Inverse(PlayerSetup.Instance.transform.rotation);
|
||||||
|
Vector3 l_targetDir = l_playerInv * (p_targetEnd.position - p_target.position);
|
||||||
|
Vector3 l_sourceDir = l_playerInv * (p_sourceEnd.position - p_source.position);
|
||||||
|
switch(p_plane)
|
||||||
|
{
|
||||||
|
case PlaneType.OXZ:
|
||||||
|
l_targetDir.y = 0f;
|
||||||
|
l_sourceDir.y = 0f;
|
||||||
|
break;
|
||||||
|
case PlaneType.OYX:
|
||||||
|
l_targetDir.z = 0f;
|
||||||
|
l_sourceDir.z = 0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
l_targetDir = Vector3.Normalize(l_targetDir);
|
||||||
|
l_sourceDir = Vector3.Normalize(l_sourceDir);
|
||||||
|
|
||||||
|
Quaternion l_targetRot = Quaternion.identity;
|
||||||
|
Quaternion l_sourceRot = Quaternion.identity;
|
||||||
|
switch(p_plane)
|
||||||
|
{
|
||||||
|
case PlaneType.OXZ:
|
||||||
|
l_targetRot = Quaternion.LookRotation(l_targetDir, Vector3.up);
|
||||||
|
l_sourceRot = Quaternion.LookRotation(l_sourceDir, Vector3.up);
|
||||||
|
break;
|
||||||
|
case PlaneType.OYX:
|
||||||
|
l_targetRot = Quaternion.LookRotation(l_targetDir, Vector3.forward);
|
||||||
|
l_sourceRot = Quaternion.LookRotation(l_sourceDir, Vector3.forward);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion l_diff = Quaternion.Inverse(l_targetRot) * l_sourceRot;
|
||||||
|
if(p_plane == PlaneType.OYX)
|
||||||
|
l_diff = Quaternion.Euler(0f, 0f, l_diff.eulerAngles.y);
|
||||||
|
|
||||||
|
Quaternion l_adjusted = l_diff * (l_playerInv * p_target.rotation);
|
||||||
|
p_target.rotation = PlayerSetup.Instance.transform.rotation * l_adjusted;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace ml_bft
|
||||||
m_bones.Clear();
|
m_bones.Clear();
|
||||||
m_localRotations.Clear();
|
m_localRotations.Clear();
|
||||||
m_renderers.Clear();
|
m_renderers.Clear();
|
||||||
|
|
||||||
Settings.ShowHandsChange -= this.OnShowHandsChange;
|
Settings.ShowHandsChange -= this.OnShowHandsChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,121 +110,113 @@ namespace ml_bft
|
||||||
public override Transform GetSourceForBone(HumanBodyBones p_bone)
|
public override Transform GetSourceForBone(HumanBodyBones p_bone)
|
||||||
{
|
{
|
||||||
Transform l_result = null;
|
Transform l_result = null;
|
||||||
if(m_left)
|
switch(p_bone)
|
||||||
{
|
{
|
||||||
switch(p_bone)
|
case HumanBodyBones.LeftHand:
|
||||||
{
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.wrist] : null);
|
||||||
case HumanBodyBones.LeftHand:
|
break;
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.wrist];
|
case HumanBodyBones.LeftThumbProximal:
|
||||||
break;
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbProximal] : null);
|
||||||
case HumanBodyBones.LeftThumbProximal:
|
break;
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbProximal];
|
case HumanBodyBones.LeftThumbIntermediate:
|
||||||
break;
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbMiddle] : null);
|
||||||
case HumanBodyBones.LeftThumbIntermediate:
|
break;
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbMiddle];
|
case HumanBodyBones.LeftThumbDistal:
|
||||||
break;
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbDistal] : null);
|
||||||
case HumanBodyBones.LeftThumbDistal:
|
break;
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbDistal];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HumanBodyBones.LeftIndexProximal:
|
case HumanBodyBones.LeftIndexProximal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexProximal];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexProximal] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.LeftIndexIntermediate:
|
case HumanBodyBones.LeftIndexIntermediate:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexMiddle];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexMiddle] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.LeftIndexDistal:
|
case HumanBodyBones.LeftIndexDistal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexDistal];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexDistal] : null);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HumanBodyBones.LeftMiddleProximal:
|
case HumanBodyBones.LeftMiddleProximal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleProximal];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleProximal] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.LeftMiddleIntermediate:
|
case HumanBodyBones.LeftMiddleIntermediate:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleMiddle];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleMiddle] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.LeftMiddleDistal:
|
case HumanBodyBones.LeftMiddleDistal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleDistal];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleDistal] : null);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HumanBodyBones.LeftRingProximal:
|
case HumanBodyBones.LeftRingProximal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringProximal];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringProximal] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.LeftRingIntermediate:
|
case HumanBodyBones.LeftRingIntermediate:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringMiddle];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringMiddle] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.LeftRingDistal:
|
case HumanBodyBones.LeftRingDistal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringDistal];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringDistal] : null);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HumanBodyBones.LeftLittleProximal:
|
case HumanBodyBones.LeftLittleProximal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyProximal];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyProximal] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.LeftLittleIntermediate:
|
case HumanBodyBones.LeftLittleIntermediate:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyMiddle];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyMiddle] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.LeftLittleDistal:
|
case HumanBodyBones.LeftLittleDistal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyDistal];
|
l_result = (m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyDistal] : null);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch(p_bone)
|
|
||||||
{
|
|
||||||
case HumanBodyBones.RightHand:
|
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.wrist];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightThumbProximal:
|
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbProximal];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightThumbIntermediate:
|
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbMiddle];
|
|
||||||
break;
|
|
||||||
case HumanBodyBones.RightThumbDistal:
|
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbDistal];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HumanBodyBones.RightIndexProximal:
|
case HumanBodyBones.RightHand:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexProximal];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.wrist] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.RightIndexIntermediate:
|
case HumanBodyBones.RightThumbProximal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexMiddle];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbProximal] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.RightIndexDistal:
|
case HumanBodyBones.RightThumbIntermediate:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexDistal];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbMiddle] : null);
|
||||||
break;
|
break;
|
||||||
|
case HumanBodyBones.RightThumbDistal:
|
||||||
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.thumbDistal] : null);
|
||||||
|
break;
|
||||||
|
|
||||||
case HumanBodyBones.RightMiddleProximal:
|
case HumanBodyBones.RightIndexProximal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleProximal];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexProximal] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.RightMiddleIntermediate:
|
case HumanBodyBones.RightIndexIntermediate:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleMiddle];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexMiddle] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.RightMiddleDistal:
|
case HumanBodyBones.RightIndexDistal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleDistal];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.indexDistal] : null);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HumanBodyBones.RightRingProximal:
|
case HumanBodyBones.RightMiddleProximal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringProximal];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleProximal] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.RightRingIntermediate:
|
case HumanBodyBones.RightMiddleIntermediate:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringMiddle];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleMiddle] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.RightRingDistal:
|
case HumanBodyBones.RightMiddleDistal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringDistal];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.middleDistal] : null);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HumanBodyBones.RightLittleProximal:
|
case HumanBodyBones.RightRingProximal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyProximal];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringProximal] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.RightLittleIntermediate:
|
case HumanBodyBones.RightRingIntermediate:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyMiddle];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringMiddle] : null);
|
||||||
break;
|
break;
|
||||||
case HumanBodyBones.RightLittleDistal:
|
case HumanBodyBones.RightRingDistal:
|
||||||
l_result = m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyDistal];
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.ringDistal] : null);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
case HumanBodyBones.RightLittleProximal:
|
||||||
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyProximal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightLittleIntermediate:
|
||||||
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyMiddle] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightLittleDistal:
|
||||||
|
l_result = (!m_left ? m_bones[(int)SteamVR_Skeleton_JointIndexEnum.pinkyDistal] : null);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return l_result;
|
return l_result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,13 +200,13 @@ namespace ml_bft
|
||||||
l_tracking.GetHandJoints(m_left ? HandTrackingFeature.Hand_Index.L : HandTrackingFeature.Hand_Index.R, out var l_positions, out var l_rotations, out _);
|
l_tracking.GetHandJoints(m_left ? HandTrackingFeature.Hand_Index.L : HandTrackingFeature.Hand_Index.R, out var l_positions, out var l_rotations, out _);
|
||||||
if(l_positions.Length >= c_fingerBonesCount)
|
if(l_positions.Length >= c_fingerBonesCount)
|
||||||
{
|
{
|
||||||
// Joints rotations are in global space, locations are in local space ... wth is wrong with OpenXR?
|
// Joints rotations are in global space, locations are in ... space??? ... wth is wrong with OpenXR?
|
||||||
Quaternion l_prefabRot = m_prefabRoot.rotation;
|
Quaternion l_prefabRot = m_prefabRoot.rotation;
|
||||||
for(int i = 0; i < c_fingerBonesCount; i++)
|
for(int i = 0; i < c_fingerBonesCount; i++)
|
||||||
{
|
{
|
||||||
if(m_bones[i] != null)
|
if(m_bones[i] != null)
|
||||||
{
|
{
|
||||||
m_bones[i].localPosition = l_positions[i];
|
//m_bones[i].localPosition = l_positions[i];
|
||||||
m_bones[i].rotation = l_prefabRot * (l_handInv * l_rotations[i]);
|
m_bones[i].rotation = l_prefabRot * (l_handInv * l_rotations[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[assembly: MelonLoader.MelonInfo(typeof(ml_bft.BetterFingersTracking), "BetterFingersTracking", "1.0.0", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
[assembly: MelonLoader.MelonInfo(typeof(ml_bft.BetterFingersTracking), "BetterFingersTracking", "1.0.1", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||||
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
[assembly: MelonLoader.MelonPlatformDomain(MelonLoader.MelonPlatformDomainAttribute.CompatibleDomains.MONO)]
|
||||||
|
|
|
@ -10,7 +10,7 @@ Mod that overhauls behaviour of fingers tracking.
|
||||||
Available mod's settings in `Settings - Input & Key-Bindings - Better Fingers Tracking`:
|
Available mod's settings in `Settings - Input & Key-Bindings - Better Fingers Tracking`:
|
||||||
* **Force SteamVR skeletal input:** forced usage of SteamVR skeletal input (works as long as controllers' driver supplies skeletal pose throught OpenVR interfaces); `false` by default
|
* **Force SteamVR skeletal input:** forced usage of SteamVR skeletal input (works as long as controllers' driver supplies skeletal pose throught OpenVR interfaces); `false` by default
|
||||||
* **Motion range:** fingers tracking motion range/mode/type; `With controller` by default
|
* **Motion range:** fingers tracking motion range/mode/type; `With controller` by default
|
||||||
* **Filter humanoid limits:** Limits fingers rotations to be valid for Unity's Mechanim; `false` by default
|
* **Filter humanoid limits:** Limits fingers rotations to be valid for Unity's Mechanim; `true` by default
|
||||||
* Note: Enabling this option ensures that visual representation of your fingers will be same for you and remote players, but it cancels out additional finger segments rotations that can be better visually in most cases.
|
* Note: Enabling this option ensures that visual representation of your fingers will be same for you and remote players, but it cancels out additional finger segments rotations that can be better visually in most cases.
|
||||||
* **Show hands model:** shows transparent hands model (mostly as debug option); `false` by default
|
* **Show hands model:** shows transparent hands model (mostly as debug option); `false` by default
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace ml_bft
|
||||||
public static bool SkeletalInput { get; private set; } = false;
|
public static bool SkeletalInput { get; private set; } = false;
|
||||||
public static MotionRangeType MotionRange { get; private set; } = MotionRangeType.WithController;
|
public static MotionRangeType MotionRange { get; private set; } = MotionRangeType.WithController;
|
||||||
public static bool ShowHands { get; private set; } = false;
|
public static bool ShowHands { get; private set; } = false;
|
||||||
public static bool MechanimFilter { get; private set; } = false;
|
public static bool MechanimFilter { get; private set; } = true;
|
||||||
|
|
||||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<Authors>SDraw</Authors>
|
<Authors>SDraw</Authors>
|
||||||
<Company>None</Company>
|
<Company>None</Company>
|
||||||
<Product>BetterFingersTracking</Product>
|
<Product>BetterFingersTracking</Product>
|
||||||
|
<Version>1.0.1</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<div class ="row-wrapper">
|
<div class ="row-wrapper">
|
||||||
<div class ="option-caption">Filter humanoid limits: </div>
|
<div class ="option-caption">Filter humanoid limits: </div>
|
||||||
<div class ="option-input">
|
<div class ="option-input">
|
||||||
<div id="MechanimFilter" class ="inp_toggle no-scroll" data-current="false"></div>
|
<div id="MechanimFilter" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace ml_lme
|
||||||
{
|
{
|
||||||
class LeapHand
|
class LeapHand
|
||||||
{
|
{
|
||||||
public enum FingerBone
|
enum FingerBone
|
||||||
{
|
{
|
||||||
ThumbMetacarpal = 0,
|
ThumbMetacarpal = 0,
|
||||||
ThumbProximal,
|
ThumbProximal,
|
||||||
|
@ -25,9 +25,12 @@ namespace ml_lme
|
||||||
PinkyMetacarpal,
|
PinkyMetacarpal,
|
||||||
PinkyProximal,
|
PinkyProximal,
|
||||||
PinkyIntermediate,
|
PinkyIntermediate,
|
||||||
PinkyDistal
|
PinkyDistal,
|
||||||
|
|
||||||
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
readonly bool m_left = false;
|
||||||
readonly Transform m_root = null;
|
readonly Transform m_root = null;
|
||||||
readonly Transform m_wrist = null;
|
readonly Transform m_wrist = null;
|
||||||
readonly GameObject m_mesh = null;
|
readonly GameObject m_mesh = null;
|
||||||
|
@ -36,14 +39,15 @@ namespace ml_lme
|
||||||
|
|
||||||
public LeapHand(Transform p_root, bool p_left)
|
public LeapHand(Transform p_root, bool p_left)
|
||||||
{
|
{
|
||||||
m_fingersBones = new Transform[20];
|
m_left = p_left;
|
||||||
m_initialRotations = new Quaternion[20];
|
m_fingersBones = new Transform[(int)FingerBone.Count];
|
||||||
|
m_initialRotations = new Quaternion[(int)FingerBone.Count];
|
||||||
|
|
||||||
m_root = p_root;
|
m_root = p_root;
|
||||||
if(m_root != null)
|
if(m_root != null)
|
||||||
{
|
{
|
||||||
m_mesh = m_root.Find(p_left ? "GenericHandL" : "GenericHandR")?.gameObject;
|
m_mesh = m_root.Find(m_left ? "GenericHandL" : "GenericHandR")?.gameObject;
|
||||||
m_wrist = m_root.Find(p_left ? "LeftHand/Wrist" : "RightHand/Wrist");
|
m_wrist = m_root.Find(m_left ? "LeftHand/Wrist" : "RightHand/Wrist");
|
||||||
if(m_wrist != null)
|
if(m_wrist != null)
|
||||||
{
|
{
|
||||||
m_fingersBones[0] = null; // Actual thumb-meta, look at Leap Motion docs, dummy, it's zero point
|
m_fingersBones[0] = null; // Actual thumb-meta, look at Leap Motion docs, dummy, it's zero point
|
||||||
|
@ -101,12 +105,14 @@ namespace ml_lme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Rebind(Quaternion p_base)
|
||||||
{
|
{
|
||||||
if(m_wrist != null)
|
if(m_wrist != null)
|
||||||
{
|
{
|
||||||
m_wrist.localPosition = Vector3.zero;
|
m_wrist.localPosition = Vector3.zero;
|
||||||
m_wrist.localRotation = Quaternion.identity;
|
m_wrist.localRotation = Quaternion.identity;
|
||||||
|
|
||||||
|
m_wrist.rotation = p_base * Quaternion.Euler(0f, m_left ? -90f : 90f, 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < 20; i++)
|
for(int i = 0; i < 20; i++)
|
||||||
|
@ -117,8 +123,111 @@ namespace ml_lme
|
||||||
}
|
}
|
||||||
|
|
||||||
public Transform GetRoot() => m_root;
|
public Transform GetRoot() => m_root;
|
||||||
public Transform GetWrist() => m_wrist;
|
public Transform GetBone(HumanBodyBones p_bone)
|
||||||
public Transform GetFingersBone(FingerBone p_bone) => m_fingersBones[(int)p_bone];
|
{
|
||||||
|
Transform l_result = null;
|
||||||
|
switch(p_bone)
|
||||||
|
{
|
||||||
|
case HumanBodyBones.LeftHand:
|
||||||
|
l_result = (m_left ? m_wrist : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftThumbProximal:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.ThumbProximal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftThumbIntermediate:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.ThumbIntermediate] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftThumbDistal:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.ThumbDistal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftIndexProximal:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.IndexProximal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftIndexIntermediate:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.IndexIntermediate] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftIndexDistal:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.IndexDistal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftMiddleProximal:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.MiddleProximal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftMiddleIntermediate:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.MiddleIntermediate] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftMiddleDistal:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.MiddleDistal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftRingProximal:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.RingProximal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftRingIntermediate:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.RingIntermediate] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftRingDistal:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.RingDistal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftLittleProximal:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.PinkyProximal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftLittleIntermediate:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.PinkyIntermediate] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.LeftLittleDistal:
|
||||||
|
l_result = (m_left ? m_fingersBones[(int)FingerBone.PinkyDistal] : null);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HumanBodyBones.RightHand:
|
||||||
|
l_result = (!m_left ? m_wrist : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightThumbProximal:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbProximal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightThumbIntermediate:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbIntermediate] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightThumbDistal:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.ThumbDistal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightIndexProximal:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexProximal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightIndexIntermediate:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexIntermediate] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightIndexDistal:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.IndexDistal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightMiddleProximal:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleProximal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightMiddleIntermediate:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleIntermediate] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightMiddleDistal:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.MiddleDistal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightRingProximal:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingProximal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightRingIntermediate:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingIntermediate] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightRingDistal:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.RingDistal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightLittleProximal:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyProximal] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightLittleIntermediate:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyIntermediate] : null);
|
||||||
|
break;
|
||||||
|
case HumanBodyBones.RightLittleDistal:
|
||||||
|
l_result = (!m_left ? m_fingersBones[(int)FingerBone.PinkyDistal] : null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return l_result;
|
||||||
|
}
|
||||||
|
|
||||||
public void SetMeshActive(bool p_state)
|
public void SetMeshActive(bool p_state)
|
||||||
{
|
{
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace ml_lme
|
||||||
m_handRayLeft.hand = true;
|
m_handRayLeft.hand = true;
|
||||||
m_handRayLeft.generalMask = -269;
|
m_handRayLeft.generalMask = -269;
|
||||||
m_handRayLeft.isInteractionRay = true;
|
m_handRayLeft.isInteractionRay = true;
|
||||||
m_handRayLeft.triggerGazeEvents = false;
|
//m_handRayLeft.triggerGazeEvents = false;
|
||||||
m_handRayLeft.holderRoot = m_handRayLeft.gameObject;
|
m_handRayLeft.holderRoot = m_handRayLeft.gameObject;
|
||||||
m_handRayLeft.attachmentDistance = 0f;
|
m_handRayLeft.attachmentDistance = 0f;
|
||||||
m_handRayLeft.uiMask = 32;
|
m_handRayLeft.uiMask = 32;
|
||||||
|
@ -60,7 +60,7 @@ namespace ml_lme
|
||||||
m_handRayRight.hand = false;
|
m_handRayRight.hand = false;
|
||||||
m_handRayRight.generalMask = -269;
|
m_handRayRight.generalMask = -269;
|
||||||
m_handRayRight.isInteractionRay = true;
|
m_handRayRight.isInteractionRay = true;
|
||||||
m_handRayRight.triggerGazeEvents = false;
|
//m_handRayRight.triggerGazeEvents = false;
|
||||||
m_handRayRight.holderRoot = m_handRayRight.gameObject;
|
m_handRayRight.holderRoot = m_handRayRight.gameObject;
|
||||||
m_handRayRight.attachmentDistance = 0f;
|
m_handRayRight.attachmentDistance = 0f;
|
||||||
m_handRayRight.uiMask = 32;
|
m_handRayRight.uiMask = 32;
|
||||||
|
|
|
@ -10,6 +10,12 @@ namespace ml_lme
|
||||||
[DefaultExecutionOrder(999999)]
|
[DefaultExecutionOrder(999999)]
|
||||||
class LeapTracked : MonoBehaviour
|
class LeapTracked : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
enum PlaneType
|
||||||
|
{
|
||||||
|
OXZ,
|
||||||
|
OYX
|
||||||
|
}
|
||||||
|
|
||||||
struct IKInfo
|
struct IKInfo
|
||||||
{
|
{
|
||||||
public Vector4 m_armsWeights;
|
public Vector4 m_armsWeights;
|
||||||
|
@ -20,50 +26,69 @@ namespace ml_lme
|
||||||
public Transform m_rightElbowTarget;
|
public Transform m_rightElbowTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FingerBoneInfo
|
struct RotationOffset
|
||||||
{
|
{
|
||||||
public LeapHand.FingerBone m_bone;
|
public Transform m_target;
|
||||||
public Transform m_targetBone;
|
public Transform m_source;
|
||||||
public Transform m_sourceBone;
|
|
||||||
public Quaternion m_offset;
|
public Quaternion m_offset;
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
m_source = null;
|
||||||
|
m_target = null;
|
||||||
|
m_offset = Quaternion.identity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static readonly Quaternion ms_offsetLeft = Quaternion.Euler(0f, 90f, 0f);
|
static readonly Quaternion ms_offsetLeft = Quaternion.Euler(0f, 90f, 0f);
|
||||||
static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 270f, 0f);
|
static readonly Quaternion ms_offsetRight = Quaternion.Euler(0f, 270f, 0f);
|
||||||
|
|
||||||
static readonly (HumanBodyBones, LeapHand.FingerBone, bool)[] ms_fingerBonesLinks =
|
static readonly (HumanBodyBones, bool)[] ms_fingers =
|
||||||
{
|
{
|
||||||
(HumanBodyBones.LeftThumbProximal, LeapHand.FingerBone.ThumbProximal, true),
|
(HumanBodyBones.LeftThumbProximal, true),
|
||||||
(HumanBodyBones.LeftThumbIntermediate, LeapHand.FingerBone.ThumbIntermediate, true),
|
(HumanBodyBones.LeftThumbIntermediate, true),
|
||||||
(HumanBodyBones.LeftThumbDistal, LeapHand.FingerBone.ThumbDistal, true),
|
(HumanBodyBones.LeftThumbDistal, true),
|
||||||
(HumanBodyBones.LeftIndexProximal, LeapHand.FingerBone.IndexProximal, true),
|
(HumanBodyBones.LeftIndexProximal, true),
|
||||||
(HumanBodyBones.LeftIndexIntermediate, LeapHand.FingerBone.IndexIntermediate, true),
|
(HumanBodyBones.LeftIndexIntermediate, true),
|
||||||
(HumanBodyBones.LeftIndexDistal, LeapHand.FingerBone.IndexDistal, true),
|
(HumanBodyBones.LeftIndexDistal, true),
|
||||||
(HumanBodyBones.LeftMiddleProximal, LeapHand.FingerBone.MiddleProximal, true),
|
(HumanBodyBones.LeftMiddleProximal, true),
|
||||||
(HumanBodyBones.LeftMiddleIntermediate, LeapHand.FingerBone.MiddleIntermediate, true),
|
(HumanBodyBones.LeftMiddleIntermediate, true),
|
||||||
(HumanBodyBones.LeftMiddleDistal, LeapHand.FingerBone.MiddleDistal, true),
|
(HumanBodyBones.LeftMiddleDistal, true),
|
||||||
(HumanBodyBones.LeftRingProximal, LeapHand.FingerBone.RingProximal, true),
|
(HumanBodyBones.LeftRingProximal, true),
|
||||||
(HumanBodyBones.LeftRingIntermediate, LeapHand.FingerBone.RingIntermediate, true),
|
(HumanBodyBones.LeftRingIntermediate, true),
|
||||||
(HumanBodyBones.LeftRingDistal, LeapHand.FingerBone.RingDistal, true),
|
(HumanBodyBones.LeftRingDistal, true),
|
||||||
(HumanBodyBones.LeftLittleProximal, LeapHand.FingerBone.PinkyProximal, true),
|
(HumanBodyBones.LeftLittleProximal, true),
|
||||||
(HumanBodyBones.LeftLittleIntermediate, LeapHand.FingerBone.PinkyIntermediate, true),
|
(HumanBodyBones.LeftLittleIntermediate, true),
|
||||||
(HumanBodyBones.LeftLittleDistal, LeapHand.FingerBone.PinkyDistal, true),
|
(HumanBodyBones.LeftLittleDistal, true),
|
||||||
|
|
||||||
(HumanBodyBones.RightThumbProximal, LeapHand.FingerBone.ThumbProximal, false),
|
(HumanBodyBones.RightThumbProximal, false),
|
||||||
(HumanBodyBones.RightThumbIntermediate, LeapHand.FingerBone.ThumbIntermediate, false),
|
(HumanBodyBones.RightThumbIntermediate, false),
|
||||||
(HumanBodyBones.RightThumbDistal, LeapHand.FingerBone.ThumbDistal, false),
|
(HumanBodyBones.RightThumbDistal, false),
|
||||||
(HumanBodyBones.RightIndexProximal, LeapHand.FingerBone.IndexProximal, false),
|
(HumanBodyBones.RightIndexProximal, false),
|
||||||
(HumanBodyBones.RightIndexIntermediate, LeapHand.FingerBone.IndexIntermediate, false),
|
(HumanBodyBones.RightIndexIntermediate, false),
|
||||||
(HumanBodyBones.RightIndexDistal, LeapHand.FingerBone.IndexDistal, false),
|
(HumanBodyBones.RightIndexDistal, false),
|
||||||
(HumanBodyBones.RightMiddleProximal, LeapHand.FingerBone.MiddleProximal, false),
|
(HumanBodyBones.RightMiddleProximal, false),
|
||||||
(HumanBodyBones.RightMiddleIntermediate, LeapHand.FingerBone.MiddleIntermediate, false),
|
(HumanBodyBones.RightMiddleIntermediate, false),
|
||||||
(HumanBodyBones.RightMiddleDistal, LeapHand.FingerBone.MiddleDistal, false),
|
(HumanBodyBones.RightMiddleDistal, false),
|
||||||
(HumanBodyBones.RightRingProximal, LeapHand.FingerBone.RingProximal, false),
|
(HumanBodyBones.RightRingProximal, false),
|
||||||
(HumanBodyBones.RightRingIntermediate, LeapHand.FingerBone.RingIntermediate, false),
|
(HumanBodyBones.RightRingIntermediate, false),
|
||||||
(HumanBodyBones.RightRingDistal, LeapHand.FingerBone.RingDistal, false),
|
(HumanBodyBones.RightRingDistal, false),
|
||||||
(HumanBodyBones.RightLittleProximal, LeapHand.FingerBone.PinkyProximal, false),
|
(HumanBodyBones.RightLittleProximal, false),
|
||||||
(HumanBodyBones.RightLittleIntermediate, LeapHand.FingerBone.PinkyIntermediate, false),
|
(HumanBodyBones.RightLittleIntermediate, false),
|
||||||
(HumanBodyBones.RightLittleDistal, LeapHand.FingerBone.PinkyDistal, false),
|
(HumanBodyBones.RightLittleDistal, false),
|
||||||
|
};
|
||||||
|
static readonly (HumanBodyBones, HumanBodyBones, bool)[] ms_rotationFixChains =
|
||||||
|
{
|
||||||
|
(HumanBodyBones.LeftThumbProximal,HumanBodyBones.LeftThumbIntermediate,true), (HumanBodyBones.LeftThumbIntermediate, HumanBodyBones.LeftThumbDistal,true),
|
||||||
|
(HumanBodyBones.LeftIndexProximal,HumanBodyBones.LeftIndexIntermediate,true), (HumanBodyBones.LeftIndexIntermediate, HumanBodyBones.LeftIndexDistal,true),
|
||||||
|
(HumanBodyBones.LeftMiddleProximal,HumanBodyBones.LeftMiddleIntermediate,true), (HumanBodyBones.LeftMiddleIntermediate, HumanBodyBones.LeftMiddleDistal,true),
|
||||||
|
(HumanBodyBones.LeftRingProximal,HumanBodyBones.LeftRingIntermediate,true), (HumanBodyBones.LeftRingIntermediate, HumanBodyBones.LeftRingDistal,true),
|
||||||
|
(HumanBodyBones.LeftLittleProximal,HumanBodyBones.LeftLittleIntermediate,true), (HumanBodyBones.LeftLittleIntermediate, HumanBodyBones.LeftLittleDistal,true),
|
||||||
|
(HumanBodyBones.RightThumbProximal,HumanBodyBones.RightThumbIntermediate,false), (HumanBodyBones.RightThumbIntermediate, HumanBodyBones.RightThumbDistal,false),
|
||||||
|
(HumanBodyBones.RightIndexProximal,HumanBodyBones.RightIndexIntermediate,false), (HumanBodyBones.RightIndexIntermediate, HumanBodyBones.RightIndexDistal,false),
|
||||||
|
(HumanBodyBones.RightMiddleProximal,HumanBodyBones.RightMiddleIntermediate,false), (HumanBodyBones.RightMiddleIntermediate, HumanBodyBones.RightMiddleDistal,false),
|
||||||
|
(HumanBodyBones.RightRingProximal,HumanBodyBones.RightRingIntermediate,false), (HumanBodyBones.RightRingIntermediate, HumanBodyBones.RightRingDistal,false),
|
||||||
|
(HumanBodyBones.RightLittleProximal,HumanBodyBones.RightLittleIntermediate,false), (HumanBodyBones.RightLittleIntermediate, HumanBodyBones.RightLittleDistal,false)
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly float[] ms_lastLeftFingerBones = new float[20];
|
public static readonly float[] ms_lastLeftFingerBones = new float[20];
|
||||||
|
@ -71,13 +96,12 @@ namespace ml_lme
|
||||||
|
|
||||||
bool m_inVR = false;
|
bool m_inVR = false;
|
||||||
VRIK m_vrIK = null;
|
VRIK m_vrIK = null;
|
||||||
|
Transform m_hips = null;
|
||||||
|
|
||||||
bool m_enabled = true;
|
bool m_enabled = true;
|
||||||
bool m_fingersOnly = false;
|
bool m_fingersOnly = false;
|
||||||
bool m_trackElbows = true;
|
bool m_trackElbows = true;
|
||||||
|
|
||||||
Transform m_leftHand = null;
|
|
||||||
Transform m_rightHand = null;
|
|
||||||
IKInfo m_vrIKInfo;
|
IKInfo m_vrIKInfo;
|
||||||
ArmIK m_leftArmIK = null;
|
ArmIK m_leftArmIK = null;
|
||||||
ArmIK m_rightArmIK = null;
|
ArmIK m_rightArmIK = null;
|
||||||
|
@ -88,16 +112,15 @@ namespace ml_lme
|
||||||
bool m_leftTargetActive = false; // VRIK only
|
bool m_leftTargetActive = false; // VRIK only
|
||||||
bool m_rightTargetActive = false; // VRIK only
|
bool m_rightTargetActive = false; // VRIK only
|
||||||
|
|
||||||
readonly List<FingerBoneInfo> m_leftFingerBones = null;
|
RotationOffset m_leftHandOffset; // From avatar hand to Leap wrist
|
||||||
readonly List<FingerBoneInfo> m_rightFingerBones = null;
|
RotationOffset m_rightHandOffset;
|
||||||
|
readonly List<RotationOffset> m_leftFingerOffsets = null; // From Leap finger bone to avatar finger bone
|
||||||
Quaternion m_leftWristOffset;
|
readonly List<RotationOffset> m_rightFingerOffsets = null;
|
||||||
Quaternion m_rightWristOffset;
|
|
||||||
|
|
||||||
internal LeapTracked()
|
internal LeapTracked()
|
||||||
{
|
{
|
||||||
m_leftFingerBones = new List<FingerBoneInfo>();
|
m_leftFingerOffsets = new List<RotationOffset>();
|
||||||
m_rightFingerBones = new List<FingerBoneInfo>();
|
m_rightFingerOffsets = new List<RotationOffset>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unity events
|
// Unity events
|
||||||
|
@ -180,17 +203,15 @@ namespace ml_lme
|
||||||
LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData();
|
LeapParser.LeapData l_data = LeapManager.Instance.GetLatestData();
|
||||||
if(l_data.m_leftHand.m_present)
|
if(l_data.m_leftHand.m_present)
|
||||||
{
|
{
|
||||||
Transform l_leapWrist = LeapTracking.Instance.GetLeftHand().GetWrist();
|
Quaternion l_turnBack = (m_leftHandOffset.m_source.rotation * m_leftHandOffset.m_offset) * Quaternion.Inverse(m_leftHandOffset.m_target.rotation);
|
||||||
Quaternion l_turnBack = (m_leftHand.rotation * m_leftWristOffset) * Quaternion.Inverse(l_leapWrist.rotation);
|
foreach(var l_info in m_leftFingerOffsets)
|
||||||
foreach(var l_info in m_leftFingerBones)
|
l_info.m_target.rotation = l_turnBack * (l_info.m_source.rotation * l_info.m_offset);
|
||||||
l_info.m_targetBone.rotation = l_turnBack * (l_info.m_sourceBone.rotation * l_info.m_offset);
|
|
||||||
}
|
}
|
||||||
if(l_data.m_rightHand.m_present)
|
if(l_data.m_rightHand.m_present)
|
||||||
{
|
{
|
||||||
Transform l_leapWrist = LeapTracking.Instance.GetRightHand().GetWrist();
|
Quaternion l_turnBack = (m_rightHandOffset.m_source.rotation * m_rightHandOffset.m_offset) * Quaternion.Inverse(m_rightHandOffset.m_target.rotation);
|
||||||
Quaternion l_turnBack = (m_rightHand.rotation * m_rightWristOffset) * Quaternion.Inverse(l_leapWrist.rotation);
|
foreach(var l_info in m_rightFingerOffsets)
|
||||||
foreach(var l_info in m_rightFingerBones)
|
l_info.m_target.rotation = l_turnBack * (l_info.m_source.rotation * l_info.m_offset);
|
||||||
l_info.m_targetBone.rotation = l_turnBack * (l_info.m_sourceBone.rotation * l_info.m_offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_poseHandler.GetHumanPose(ref m_pose);
|
m_poseHandler.GetHumanPose(ref m_pose);
|
||||||
|
@ -211,6 +232,15 @@ namespace ml_lme
|
||||||
ms_lastRightFingerBones[l_offset + 3] = m_pose.muscles[(int)MuscleIndex.RightThumbSpread + l_offset];
|
ms_lastRightFingerBones[l_offset + 3] = m_pose.muscles[(int)MuscleIndex.RightThumbSpread + l_offset];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Settings.MechanimFilter && (m_hips != null))
|
||||||
|
{
|
||||||
|
// Yoinked from IKSystem.OnPostSolverUpdateGeneral
|
||||||
|
Vector3 l_pos = m_hips.position;
|
||||||
|
Quaternion l_rot = m_hips.rotation;
|
||||||
|
m_poseHandler.SetHumanPose(ref m_pose);
|
||||||
|
m_hips.SetPositionAndRotation(l_pos, l_rot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +248,7 @@ namespace ml_lme
|
||||||
internal void OnAvatarClear()
|
internal void OnAvatarClear()
|
||||||
{
|
{
|
||||||
m_vrIK = null;
|
m_vrIK = null;
|
||||||
|
m_hips = null;
|
||||||
m_leftArmIK = null;
|
m_leftArmIK = null;
|
||||||
m_rightArmIK = null;
|
m_rightArmIK = null;
|
||||||
m_leftTargetActive = false;
|
m_leftTargetActive = false;
|
||||||
|
@ -231,13 +262,11 @@ namespace ml_lme
|
||||||
m_rightHandTarget.localPosition = Vector3.zero;
|
m_rightHandTarget.localPosition = Vector3.zero;
|
||||||
m_rightHandTarget.localRotation = Quaternion.identity;
|
m_rightHandTarget.localRotation = Quaternion.identity;
|
||||||
|
|
||||||
m_leftFingerBones.Clear();
|
m_leftHandOffset.Reset();
|
||||||
m_rightFingerBones.Clear();
|
m_rightHandOffset.Reset();
|
||||||
|
|
||||||
m_leftHand = null;
|
m_leftFingerOffsets.Clear();
|
||||||
m_rightHand = null;
|
m_rightFingerOffsets.Clear();
|
||||||
m_leftWristOffset = Quaternion.identity;
|
|
||||||
m_rightWristOffset = Quaternion.identity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnAvatarSetup()
|
internal void OnAvatarSetup()
|
||||||
|
@ -251,11 +280,13 @@ namespace ml_lme
|
||||||
m_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._animator.transform);
|
m_poseHandler = new HumanPoseHandler(PlayerSetup.Instance._animator.avatar, PlayerSetup.Instance._animator.transform);
|
||||||
m_poseHandler.GetHumanPose(ref m_pose);
|
m_poseHandler.GetHumanPose(ref m_pose);
|
||||||
|
|
||||||
m_leftHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
m_hips = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.Hips);
|
||||||
m_leftHandTarget.localRotation = ms_offsetLeft * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_leftHand.rotation);
|
|
||||||
|
|
||||||
m_rightHand = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
|
m_leftHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||||
m_rightHandTarget.localRotation = ms_offsetRight * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_rightHand.rotation);
|
m_leftHandTarget.localRotation = ms_offsetLeft * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_leftHandOffset.m_source.rotation);
|
||||||
|
|
||||||
|
m_rightHandOffset.m_source = PlayerSetup.Instance._animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||||
|
m_rightHandTarget.localRotation = ms_offsetRight * (Quaternion.Inverse(PlayerSetup.Instance._avatar.transform.rotation) * m_rightHandOffset.m_source.rotation);
|
||||||
|
|
||||||
ParseFingersBones();
|
ParseFingersBones();
|
||||||
|
|
||||||
|
@ -441,31 +472,96 @@ namespace ml_lme
|
||||||
|
|
||||||
void ParseFingersBones()
|
void ParseFingersBones()
|
||||||
{
|
{
|
||||||
LeapTracking.Instance.GetLeftHand().Reset();
|
LeapTracking.Instance.Rebind(PlayerSetup.Instance.transform.rotation);
|
||||||
LeapTracking.Instance.GetLeftHand().GetWrist().rotation = PlayerSetup.Instance.transform.rotation * ms_offsetRight; // Weird, but that's how it works
|
|
||||||
m_leftWristOffset = Quaternion.Inverse(m_leftHand.rotation) * LeapTracking.Instance.GetLeftHand().GetWrist().rotation;
|
|
||||||
|
|
||||||
LeapTracking.Instance.GetRightHand().Reset();
|
// Try to "fix" rotations, slightly inaccurate after 0YX plane rotation
|
||||||
LeapTracking.Instance.GetRightHand().GetWrist().rotation = PlayerSetup.Instance.transform.rotation * ms_offsetLeft; // Weird, but that's how it works
|
foreach(var l_tuple in ms_rotationFixChains)
|
||||||
m_rightWristOffset = Quaternion.Inverse(m_rightHand.rotation) * LeapTracking.Instance.GetRightHand().GetWrist().rotation;
|
{
|
||||||
|
ReorientateTowards(
|
||||||
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
||||||
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
||||||
|
l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item1) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item1),
|
||||||
|
l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item2) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item2),
|
||||||
|
PlaneType.OXZ
|
||||||
|
);
|
||||||
|
ReorientateTowards(
|
||||||
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item1),
|
||||||
|
PlayerSetup.Instance._animator.GetBoneTransform(l_tuple.Item2),
|
||||||
|
l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item1) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item1),
|
||||||
|
l_tuple.Item3 ? LeapTracking.Instance.GetLeftHand().GetBone(l_tuple.Item2) : LeapTracking.Instance.GetRightHand().GetBone(l_tuple.Item2),
|
||||||
|
PlaneType.OYX
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
foreach(var l_link in ms_fingerBonesLinks)
|
// Bind
|
||||||
|
m_leftHandOffset.m_target = LeapTracking.Instance.GetLeftHand().GetBone(HumanBodyBones.LeftHand);
|
||||||
|
if((m_leftHandOffset.m_source != null) && (m_leftHandOffset.m_target != null))
|
||||||
|
m_leftHandOffset.m_offset = Quaternion.Inverse(m_leftHandOffset.m_source.rotation) * m_leftHandOffset.m_target.rotation;
|
||||||
|
|
||||||
|
m_rightHandOffset.m_target = LeapTracking.Instance.GetRightHand().GetBone(HumanBodyBones.RightHand);
|
||||||
|
if((m_rightHandOffset.m_source != null) && (m_rightHandOffset.m_target != null))
|
||||||
|
m_rightHandOffset.m_offset = Quaternion.Inverse(m_rightHandOffset.m_source.rotation) * m_rightHandOffset.m_target.rotation;
|
||||||
|
|
||||||
|
foreach(var l_link in ms_fingers)
|
||||||
{
|
{
|
||||||
Transform l_transform = PlayerSetup.Instance._animator.GetBoneTransform(l_link.Item1);
|
Transform l_transform = PlayerSetup.Instance._animator.GetBoneTransform(l_link.Item1);
|
||||||
if(l_transform != null)
|
if(l_transform != null)
|
||||||
{
|
{
|
||||||
FingerBoneInfo l_info = new FingerBoneInfo();
|
RotationOffset l_offset = new RotationOffset();
|
||||||
l_info.m_bone = l_link.Item2;
|
l_offset.m_target = l_transform;
|
||||||
l_info.m_targetBone = l_transform;
|
l_offset.m_source = (l_link.Item2 ? LeapTracking.Instance.GetLeftHand().GetBone(l_link.Item1) : LeapTracking.Instance.GetRightHand().GetBone(l_link.Item1));
|
||||||
l_info.m_sourceBone = (l_link.Item3 ? LeapTracking.Instance.GetLeftHand().GetFingersBone(l_link.Item2) : LeapTracking.Instance.GetRightHand().GetFingersBone(l_link.Item2));
|
l_offset.m_offset = Quaternion.Inverse(l_offset.m_source.rotation) * l_offset.m_target.rotation;
|
||||||
l_info.m_offset = Quaternion.Inverse(l_info.m_sourceBone.rotation) * l_info.m_targetBone.rotation;
|
|
||||||
|
|
||||||
if(l_link.Item3)
|
if(l_link.Item2)
|
||||||
m_leftFingerBones.Add(l_info);
|
m_leftFingerOffsets.Add(l_offset);
|
||||||
else
|
else
|
||||||
m_rightFingerBones.Add(l_info);
|
m_rightFingerOffsets.Add(l_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReorientateTowards(Transform p_target, Transform p_targetEnd, Transform p_source, Transform p_sourceEnd, PlaneType p_plane)
|
||||||
|
{
|
||||||
|
if((p_target != null) && (p_targetEnd != null) && (p_source != null) && (p_sourceEnd != null))
|
||||||
|
{
|
||||||
|
Quaternion l_playerInv = Quaternion.Inverse(PlayerSetup.Instance.transform.rotation);
|
||||||
|
Vector3 l_targetDir = l_playerInv * (p_targetEnd.position - p_target.position);
|
||||||
|
Vector3 l_sourceDir = l_playerInv * (p_sourceEnd.position - p_source.position);
|
||||||
|
switch(p_plane)
|
||||||
|
{
|
||||||
|
case PlaneType.OXZ:
|
||||||
|
l_targetDir.y = 0f;
|
||||||
|
l_sourceDir.y = 0f;
|
||||||
|
break;
|
||||||
|
case PlaneType.OYX:
|
||||||
|
l_targetDir.z = 0f;
|
||||||
|
l_sourceDir.z = 0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
l_targetDir = Vector3.Normalize(l_targetDir);
|
||||||
|
l_sourceDir = Vector3.Normalize(l_sourceDir);
|
||||||
|
|
||||||
|
Quaternion l_targetRot = Quaternion.identity;
|
||||||
|
Quaternion l_sourceRot = Quaternion.identity;
|
||||||
|
switch(p_plane)
|
||||||
|
{
|
||||||
|
case PlaneType.OXZ:
|
||||||
|
l_targetRot = Quaternion.LookRotation(l_targetDir, Vector3.up);
|
||||||
|
l_sourceRot = Quaternion.LookRotation(l_sourceDir, Vector3.up);
|
||||||
|
break;
|
||||||
|
case PlaneType.OYX:
|
||||||
|
l_targetRot = Quaternion.LookRotation(l_targetDir, Vector3.forward);
|
||||||
|
l_sourceRot = Quaternion.LookRotation(l_sourceDir, Vector3.forward);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion l_diff = Quaternion.Inverse(l_targetRot) * l_sourceRot;
|
||||||
|
if(p_plane == PlaneType.OYX)
|
||||||
|
l_diff = Quaternion.Euler(0f, 0f, l_diff.eulerAngles.y);
|
||||||
|
|
||||||
|
Quaternion l_adjusted = l_diff * (l_playerInv * p_target.rotation);
|
||||||
|
p_target.rotation = PlayerSetup.Instance.transform.rotation * l_adjusted;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ namespace ml_lme
|
||||||
GameObject m_leapHands = null;
|
GameObject m_leapHands = null;
|
||||||
LeapHand m_leapHandLeft = null;
|
LeapHand m_leapHandLeft = null;
|
||||||
LeapHand m_leapHandRight = null;
|
LeapHand m_leapHandRight = null;
|
||||||
GameObject m_leapElbowLeft = null;
|
Transform m_leapElbowLeft = null;
|
||||||
GameObject m_leapElbowRight = null;
|
Transform m_leapElbowRight = null;
|
||||||
GameObject m_leapControllerModel = null;
|
GameObject m_leapControllerModel = null;
|
||||||
|
|
||||||
float m_scaleRelation = 1f;
|
float m_scaleRelation = 1f;
|
||||||
|
@ -31,15 +31,15 @@ namespace ml_lme
|
||||||
|
|
||||||
m_inVR = Utils.IsInVR();
|
m_inVR = Utils.IsInVR();
|
||||||
|
|
||||||
m_leapElbowLeft = new GameObject("LeapElbowLeft");
|
m_leapElbowLeft = new GameObject("LeapElbowLeft").transform;
|
||||||
m_leapElbowLeft.transform.parent = this.transform;
|
m_leapElbowLeft.parent = this.transform;
|
||||||
m_leapElbowLeft.transform.localPosition = Vector3.zero;
|
m_leapElbowLeft.localPosition = Vector3.zero;
|
||||||
m_leapElbowLeft.transform.localRotation = Quaternion.identity;
|
m_leapElbowLeft.localRotation = Quaternion.identity;
|
||||||
|
|
||||||
m_leapElbowRight = new GameObject("LeapElbowRight");
|
m_leapElbowRight = new GameObject("LeapElbowRight").transform;
|
||||||
m_leapElbowRight.transform.parent = this.transform;
|
m_leapElbowRight.parent = this.transform;
|
||||||
m_leapElbowRight.transform.localPosition = Vector3.zero;
|
m_leapElbowRight.localPosition = Vector3.zero;
|
||||||
m_leapElbowRight.transform.localRotation = Quaternion.identity;
|
m_leapElbowRight.localRotation = Quaternion.identity;
|
||||||
|
|
||||||
m_leapControllerModel = AssetsHandler.GetAsset("assets/models/leapmotion/leap_motion_1_0.obj");
|
m_leapControllerModel = AssetsHandler.GetAsset("assets/models/leapmotion/leap_motion_1_0.obj");
|
||||||
if(m_leapControllerModel != null)
|
if(m_leapControllerModel != null)
|
||||||
|
@ -101,11 +101,11 @@ namespace ml_lme
|
||||||
m_leapHandRight = null;
|
m_leapHandRight = null;
|
||||||
|
|
||||||
if(m_leapElbowLeft != null)
|
if(m_leapElbowLeft != null)
|
||||||
Object.Destroy(m_leapElbowLeft);
|
Object.Destroy(m_leapElbowLeft.gameObject);
|
||||||
m_leapElbowLeft = null;
|
m_leapElbowLeft = null;
|
||||||
|
|
||||||
if(m_leapElbowRight != null)
|
if(m_leapElbowRight != null)
|
||||||
Object.Destroy(m_leapElbowRight);
|
Object.Destroy(m_leapElbowRight.gameObject);
|
||||||
m_leapElbowRight = null;
|
m_leapElbowRight = null;
|
||||||
|
|
||||||
if(m_leapControllerModel != null)
|
if(m_leapControllerModel != null)
|
||||||
|
@ -140,7 +140,7 @@ namespace ml_lme
|
||||||
m_leapHandLeft.GetRoot().localRotation = l_data.m_leftHand.m_rotation;
|
m_leapHandLeft.GetRoot().localRotation = l_data.m_leftHand.m_rotation;
|
||||||
|
|
||||||
OrientationAdjustment(ref l_data.m_leftHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode);
|
OrientationAdjustment(ref l_data.m_leftHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode);
|
||||||
m_leapElbowLeft.transform.localPosition = l_data.m_leftHand.m_elbowPosition;
|
m_leapElbowLeft.localPosition = l_data.m_leftHand.m_elbowPosition;
|
||||||
|
|
||||||
m_leapHandLeft?.Update(l_data.m_leftHand);
|
m_leapHandLeft?.Update(l_data.m_leftHand);
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ namespace ml_lme
|
||||||
m_leapHandRight.GetRoot().localRotation = l_data.m_rightHand.m_rotation;
|
m_leapHandRight.GetRoot().localRotation = l_data.m_rightHand.m_rotation;
|
||||||
|
|
||||||
OrientationAdjustment(ref l_data.m_rightHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode);
|
OrientationAdjustment(ref l_data.m_rightHand.m_elbowPosition, ref ms_dummyRotation, Settings.TrackingMode);
|
||||||
m_leapElbowRight.transform.localPosition = l_data.m_rightHand.m_elbowPosition;
|
m_leapElbowRight.localPosition = l_data.m_rightHand.m_elbowPosition;
|
||||||
|
|
||||||
m_leapHandRight?.Update(l_data.m_rightHand);
|
m_leapHandRight?.Update(l_data.m_rightHand);
|
||||||
}
|
}
|
||||||
|
@ -164,8 +164,13 @@ namespace ml_lme
|
||||||
|
|
||||||
public LeapHand GetLeftHand() => m_leapHandLeft;
|
public LeapHand GetLeftHand() => m_leapHandLeft;
|
||||||
public LeapHand GetRightHand() => m_leapHandRight;
|
public LeapHand GetRightHand() => m_leapHandRight;
|
||||||
public Transform GetLeftElbow() => m_leapElbowLeft.transform;
|
public Transform GetLeftElbow() => m_leapElbowLeft;
|
||||||
public Transform GetRightElbow() => m_leapElbowRight.transform;
|
public Transform GetRightElbow() => m_leapElbowRight;
|
||||||
|
public void Rebind(Quaternion p_base)
|
||||||
|
{
|
||||||
|
m_leapHandLeft?.Rebind(p_base);
|
||||||
|
m_leapHandRight?.Rebind(p_base);
|
||||||
|
}
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
void OnDesktopOffsetChange(Vector3 p_offset)
|
void OnDesktopOffsetChange(Vector3 p_offset)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.6", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
[assembly: MelonLoader.MelonInfo(typeof(ml_lme.LeapMotionExtension), "LeapMotionExtension", "1.4.7", "SDraw", "https://github.com/SDraw/ml_mods_cvr")]
|
||||||
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
[assembly: MelonLoader.MelonGame(null, "ChilloutVR")]
|
||||||
[assembly: MelonLoader.MelonOptionalDependencies("ml_pmc")]
|
[assembly: MelonLoader.MelonOptionalDependencies("ml_pmc")]
|
||||||
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
[assembly: MelonLoader.MelonPlatform(MelonLoader.MelonPlatformAttribute.CompatiblePlatforms.WINDOWS_X64)]
|
||||||
|
|
|
@ -25,3 +25,5 @@ Available mod's settings in `Settings - Implementation - Leap Motion Tracking`:
|
||||||
* **Recognize gestures:** sets avatar gestures (fist, gun, rock'n'roll and etc.) based on current fingers pose; `false` by default.
|
* **Recognize gestures:** sets avatar gestures (fist, gun, rock'n'roll and etc.) based on current fingers pose; `false` by default.
|
||||||
* **Interact gesture threadhold:** activation limit for interaction based on hand gesture; 80 by default.
|
* **Interact gesture threadhold:** activation limit for interaction based on hand gesture; 80 by default.
|
||||||
* **Grip gesture threadhold:** activation limit for grip based on hand gesture; 40 by default.
|
* **Grip gesture threadhold:** activation limit for grip based on hand gesture; 40 by default.
|
||||||
|
* **Filter humanoid limits:** Limits fingers rotations to be valid for Unity's Mechanim; `true` by default
|
||||||
|
* Note: Enabling this option ensures that visual representation of your fingers will be same for you and remote players, but it cancels out additional finger segments rotations that can be better visually in most cases.
|
||||||
|
|
|
@ -35,7 +35,8 @@ namespace ml_lme
|
||||||
Gestures,
|
Gestures,
|
||||||
InteractThreadhold,
|
InteractThreadhold,
|
||||||
GripThreadhold,
|
GripThreadhold,
|
||||||
VisualHands
|
VisualHands,
|
||||||
|
MechanimFilter
|
||||||
};
|
};
|
||||||
|
|
||||||
public static bool Enabled { get; private set; } = false;
|
public static bool Enabled { get; private set; } = false;
|
||||||
|
@ -52,6 +53,7 @@ namespace ml_lme
|
||||||
public static float InteractThreadhold { get; private set; } = 0.8f;
|
public static float InteractThreadhold { get; private set; } = 0.8f;
|
||||||
public static float GripThreadhold { get; private set; } = 0.4f;
|
public static float GripThreadhold { get; private set; } = 0.4f;
|
||||||
public static bool VisualHands { get; private set; } = false;
|
public static bool VisualHands { get; private set; } = false;
|
||||||
|
public static bool MechanimFilter { get; private set; } = true;
|
||||||
|
|
||||||
static MelonLoader.MelonPreferences_Category ms_category = null;
|
static MelonLoader.MelonPreferences_Category ms_category = null;
|
||||||
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
static List<MelonLoader.MelonPreferences_Entry> ms_entries = null;
|
||||||
|
@ -70,6 +72,7 @@ namespace ml_lme
|
||||||
public static event Action<float> InteractThreadholdChange;
|
public static event Action<float> InteractThreadholdChange;
|
||||||
public static event Action<float> GripThreadholdChange;
|
public static event Action<float> GripThreadholdChange;
|
||||||
public static event Action<bool> VisualHandsChange;
|
public static event Action<bool> VisualHandsChange;
|
||||||
|
public static event Action<bool> MechanimFilterChange;
|
||||||
|
|
||||||
internal static void Init()
|
internal static void Init()
|
||||||
{
|
{
|
||||||
|
@ -96,7 +99,8 @@ namespace ml_lme
|
||||||
ms_category.CreateEntry(ModSetting.Gestures.ToString(), Gestures),
|
ms_category.CreateEntry(ModSetting.Gestures.ToString(), Gestures),
|
||||||
ms_category.CreateEntry(ModSetting.InteractThreadhold.ToString(), (int)(InteractThreadhold * 100f)),
|
ms_category.CreateEntry(ModSetting.InteractThreadhold.ToString(), (int)(InteractThreadhold * 100f)),
|
||||||
ms_category.CreateEntry(ModSetting.GripThreadhold.ToString(), (int)(GripThreadhold * 100f)),
|
ms_category.CreateEntry(ModSetting.GripThreadhold.ToString(), (int)(GripThreadhold * 100f)),
|
||||||
ms_category.CreateEntry(ModSetting.VisualHands.ToString(), VisualHands)
|
ms_category.CreateEntry(ModSetting.VisualHands.ToString(), VisualHands),
|
||||||
|
ms_category.CreateEntry(ModSetting.MechanimFilter.ToString(), MechanimFilter)
|
||||||
};
|
};
|
||||||
|
|
||||||
Load();
|
Load();
|
||||||
|
@ -156,6 +160,7 @@ namespace ml_lme
|
||||||
InteractThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f;
|
InteractThreadhold = (int)ms_entries[(int)ModSetting.InteractThreadhold].BoxedValue * 0.01f;
|
||||||
GripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f;
|
GripThreadhold = (int)ms_entries[(int)ModSetting.GripThreadhold].BoxedValue * 0.01f;
|
||||||
VisualHands = (bool)ms_entries[(int)ModSetting.VisualHands].BoxedValue;
|
VisualHands = (bool)ms_entries[(int)ModSetting.VisualHands].BoxedValue;
|
||||||
|
MechanimFilter = (bool)ms_entries[(int)ModSetting.MechanimFilter].BoxedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnToggleUpdate(string p_name, string p_value)
|
static void OnToggleUpdate(string p_name, string p_value)
|
||||||
|
@ -219,6 +224,13 @@ namespace ml_lme
|
||||||
VisualHandsChange?.Invoke(VisualHands);
|
VisualHandsChange?.Invoke(VisualHands);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ModSetting.MechanimFilter:
|
||||||
|
{
|
||||||
|
MechanimFilter = bool.Parse(p_value);
|
||||||
|
MechanimFilterChange?.Invoke(MechanimFilter);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
ms_entries[(int)l_setting].BoxedValue = bool.Parse(p_value);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<Platforms>x64</Platforms>
|
<Platforms>x64</Platforms>
|
||||||
<PackageId>LeapMotionExtension</PackageId>
|
<PackageId>LeapMotionExtension</PackageId>
|
||||||
<Version>1.4.6</Version>
|
<Version>1.4.7</Version>
|
||||||
<Authors>SDraw</Authors>
|
<Authors>SDraw</Authors>
|
||||||
<Company>None</Company>
|
<Company>None</Company>
|
||||||
<Product>LeapMotionExtension</Product>
|
<Product>LeapMotionExtension</Product>
|
||||||
|
|
|
@ -145,6 +145,13 @@
|
||||||
<div id="GripThreadhold" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="40"></div>
|
<div id="GripThreadhold" class ="inp_slider no-scroll" data-min="0" data-max="100" data-current="40"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class ="row-wrapper">
|
||||||
|
<div class ="option-caption">Filter humanoid limits: </div>
|
||||||
|
<div class ="option-input">
|
||||||
|
<div id="MechanimFilter" class ="inp_toggle no-scroll" data-current="true"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
document.getElementById('settings-implementation').appendChild(l_block);
|
document.getElementById('settings-implementation').appendChild(l_block);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue