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