mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-03 23:09: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"?>
|
<?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.CCK.Components;
|
||||||
using ABI_RC.Core.Base;
|
|
||||||
using ABI_RC.Core.Player;
|
using ABI_RC.Core.Player;
|
||||||
using ABI_RC.Systems.IK;
|
|
||||||
using ABI_RC.Systems.IK.SubSystems;
|
using ABI_RC.Systems.IK.SubSystems;
|
||||||
using ABI_RC.Systems.MovementSystem;
|
using ABI_RC.Systems.MovementSystem;
|
||||||
|
using NAK.DesktopVRIK.VRIKHelper;
|
||||||
using RootMotion.FinalIK;
|
using RootMotion.FinalIK;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
|
||||||
|
|
||||||
namespace NAK.DesktopVRIK;
|
namespace NAK.DesktopVRIK;
|
||||||
|
|
||||||
internal class DesktopVRIKSystem : MonoBehaviour
|
internal class DesktopVRIKSystem : MonoBehaviour
|
||||||
{
|
{
|
||||||
public static DesktopVRIKSystem Instance;
|
public static DesktopVRIKSystem Instance;
|
||||||
public static Dictionary<HumanBodyBones, bool> BoneExists;
|
public static DesktopVRIKCalibrator Calibrator;
|
||||||
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
|
// VRIK Calibration Info
|
||||||
{
|
public VRIKCalibrationData calibrationData;
|
||||||
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;
|
|
||||||
|
|
||||||
// Avatar Components
|
// Avatar Components
|
||||||
public CVRAvatar avatarDescriptor = null;
|
|
||||||
public Animator avatarAnimator = null;
|
|
||||||
public Transform avatarTransform = null;
|
|
||||||
public LookAtIK avatarLookAtIK = null;
|
|
||||||
public VRIK avatarVRIK = null;
|
public VRIK avatarVRIK = null;
|
||||||
public IKSolverVR avatarIKSolver = null;
|
public LookAtIK avatarLookAtIK = null;
|
||||||
|
public Transform avatarTransform = null;
|
||||||
|
public CachedSolver cachedSolver;
|
||||||
|
|
||||||
// ChilloutVR Player Components
|
// ChilloutVR Player Components
|
||||||
PlayerSetup playerSetup;
|
PlayerSetup playerSetup;
|
||||||
MovementSystem movementSystem;
|
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
|
// Player Info
|
||||||
Transform _cameraTransform;
|
Transform _cameraTransform;
|
||||||
bool _ikEmotePlaying;
|
bool _ikEmotePlaying;
|
||||||
|
@ -186,21 +39,16 @@ internal class DesktopVRIKSystem : MonoBehaviour
|
||||||
Quaternion _movementRotation;
|
Quaternion _movementRotation;
|
||||||
CVRMovementParent _movementParent;
|
CVRMovementParent _movementParent;
|
||||||
|
|
||||||
DesktopVRIKSystem()
|
|
||||||
{
|
|
||||||
BoneExists = new Dictionary<HumanBodyBones, bool>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
Instance = this;
|
Instance = this;
|
||||||
|
|
||||||
|
Calibrator = new DesktopVRIKCalibrator();
|
||||||
|
|
||||||
playerSetup = GetComponent<PlayerSetup>();
|
playerSetup = GetComponent<PlayerSetup>();
|
||||||
movementSystem = GetComponent<MovementSystem>();
|
movementSystem = GetComponent<MovementSystem>();
|
||||||
|
|
||||||
_cameraTransform = playerSetup.desktopCamera.transform;
|
_cameraTransform = playerSetup.desktopCamera.transform;
|
||||||
|
|
||||||
DesktopVRIK.UpdateAllSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
|
@ -220,7 +68,7 @@ internal class DesktopVRIKSystem : MonoBehaviour
|
||||||
if (shouldTrackLocomotion != BodySystem.TrackingLocomotionEnabled)
|
if (shouldTrackLocomotion != BodySystem.TrackingLocomotionEnabled)
|
||||||
{
|
{
|
||||||
BodySystem.TrackingLocomotionEnabled = shouldTrackLocomotion;
|
BodySystem.TrackingLocomotionEnabled = shouldTrackLocomotion;
|
||||||
avatarIKSolver.Reset();
|
IKResetSolver();
|
||||||
ResetDesktopVRIK();
|
ResetDesktopVRIK();
|
||||||
if (shouldTrackLocomotion) IKResetFootsteps();
|
if (shouldTrackLocomotion) IKResetFootsteps();
|
||||||
}
|
}
|
||||||
|
@ -242,29 +90,26 @@ internal class DesktopVRIKSystem : MonoBehaviour
|
||||||
bool IsStanding()
|
bool IsStanding()
|
||||||
{
|
{
|
||||||
// Let AMT handle it if available
|
// Let AMT handle it if available
|
||||||
if (Setting_IntegrationAMT) return true;
|
if (DesktopVRIK.EntryIntegrationAMT.Value) return true;
|
||||||
|
|
||||||
// Get Upright value
|
// 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;
|
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;
|
return upright > 0.85f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UpdateLocomotionWeight()
|
void UpdateLocomotionWeight()
|
||||||
{
|
{
|
||||||
float targetWeight = BodySystem.TrackingEnabled && BodySystem.TrackingLocomotionEnabled ? 1.0f : 0.0f;
|
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);
|
_ikWeightLerp = Mathf.Lerp(_ikWeightLerp, targetWeight, Time.deltaTime * DesktopVRIK.EntryIKLerpSpeed.Value);
|
||||||
_locomotionWeight = Mathf.Lerp(_locomotionWeight, targetWeight, Time.deltaTime * Setting_IKLerpSpeed * 2f);
|
_locomotionWeight = Mathf.Lerp(_locomotionWeight, targetWeight, Time.deltaTime * DesktopVRIK.EntryIKLerpSpeed.Value * 2f);
|
||||||
}
|
return;
|
||||||
else
|
|
||||||
{
|
|
||||||
_ikWeightLerp = targetWeight;
|
|
||||||
_locomotionWeight = targetWeight;
|
|
||||||
}
|
}
|
||||||
|
_ikWeightLerp = targetWeight;
|
||||||
|
_locomotionWeight = targetWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyBodySystemWeights()
|
void ApplyBodySystemWeights()
|
||||||
|
@ -281,32 +126,33 @@ internal class DesktopVRIKSystem : MonoBehaviour
|
||||||
leg.positionWeight = isTracked ? 1f : 0f;
|
leg.positionWeight = isTracked ? 1f : 0f;
|
||||||
leg.rotationWeight = isTracked ? 1f : 0f;
|
leg.rotationWeight = isTracked ? 1f : 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BodySystem.TrackingEnabled)
|
if (BodySystem.TrackingEnabled)
|
||||||
{
|
{
|
||||||
avatarVRIK.enabled = true;
|
avatarVRIK.enabled = true;
|
||||||
avatarIKSolver.IKPositionWeight = BodySystem.TrackingPositionWeight;
|
cachedSolver.Solver.IKPositionWeight = BodySystem.TrackingPositionWeight;
|
||||||
avatarIKSolver.locomotion.weight = _locomotionWeight;
|
cachedSolver.Locomotion.weight = _locomotionWeight;
|
||||||
|
|
||||||
bool useAnimatedBendNormal = _locomotionWeight <= 0.5f;
|
bool useAnimatedBendNormal = _locomotionWeight <= 0.5f;
|
||||||
avatarIKSolver.leftLeg.useAnimatedBendNormal = useAnimatedBendNormal;
|
cachedSolver.LeftLeg.useAnimatedBendNormal = useAnimatedBendNormal;
|
||||||
avatarIKSolver.rightLeg.useAnimatedBendNormal = useAnimatedBendNormal;
|
cachedSolver.RightLeg.useAnimatedBendNormal = useAnimatedBendNormal;
|
||||||
SetArmWeight(avatarIKSolver.leftArm, BodySystem.TrackingLeftArmEnabled && avatarIKSolver.leftArm.target != null);
|
SetArmWeight(cachedSolver.LeftArm, BodySystem.TrackingLeftArmEnabled && cachedSolver.LeftArm.target != null);
|
||||||
SetArmWeight(avatarIKSolver.rightArm, BodySystem.TrackingRightArmEnabled && avatarIKSolver.rightArm.target != null);
|
SetArmWeight(cachedSolver.RightArm, BodySystem.TrackingRightArmEnabled && cachedSolver.RightArm.target != null);
|
||||||
SetLegWeight(avatarIKSolver.leftLeg, BodySystem.TrackingLeftLegEnabled && avatarIKSolver.leftLeg.target != null);
|
SetLegWeight(cachedSolver.LeftLeg, BodySystem.TrackingLeftLegEnabled && cachedSolver.LeftLeg.target != null);
|
||||||
SetLegWeight(avatarIKSolver.rightLeg, BodySystem.TrackingRightLegEnabled && avatarIKSolver.rightLeg.target != null);
|
SetLegWeight(cachedSolver.RightLeg, BodySystem.TrackingRightLegEnabled && cachedSolver.RightLeg.target != null);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
avatarVRIK.enabled = false;
|
avatarVRIK.enabled = false;
|
||||||
avatarIKSolver.IKPositionWeight = 0f;
|
cachedSolver.Solver.IKPositionWeight = 0f;
|
||||||
avatarIKSolver.locomotion.weight = 0f;
|
cachedSolver.Locomotion.weight = 0f;
|
||||||
|
|
||||||
avatarIKSolver.leftLeg.useAnimatedBendNormal = false;
|
cachedSolver.LeftLeg.useAnimatedBendNormal = false;
|
||||||
avatarIKSolver.rightLeg.useAnimatedBendNormal = false;
|
cachedSolver.RightLeg.useAnimatedBendNormal = false;
|
||||||
SetArmWeight(avatarIKSolver.leftArm, false);
|
SetArmWeight(cachedSolver.LeftArm, false);
|
||||||
SetArmWeight(avatarIKSolver.rightArm, false);
|
SetArmWeight(cachedSolver.RightArm, false);
|
||||||
SetLegWeight(avatarIKSolver.leftLeg, false);
|
SetLegWeight(cachedSolver.LeftLeg, false);
|
||||||
SetLegWeight(avatarIKSolver.rightLeg, false);
|
SetLegWeight(cachedSolver.RightLeg, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,42 +165,26 @@ internal class DesktopVRIKSystem : MonoBehaviour
|
||||||
|
|
||||||
public void OnSetupAvatarDesktop(Animator animator)
|
public void OnSetupAvatarDesktop(Animator animator)
|
||||||
{
|
{
|
||||||
if (!Setting_Enabled) return;
|
if (!DesktopVRIK.EntryEnabled.Value) return;
|
||||||
|
|
||||||
// only run for humanoid avatars
|
// only run for humanoid avatars
|
||||||
if (animator != null && animator.avatar != null && animator.avatar.isHuman)
|
if (animator != null && animator.avatar != null && animator.avatar.isHuman)
|
||||||
{
|
{
|
||||||
CalibrateDesktopVRIK();
|
Calibrator.CalibrateDesktopVRIK(animator);
|
||||||
ResetDesktopVRIK();
|
ResetDesktopVRIK();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool OnSetupIKScaling(float scaleDifference)
|
public void OnSetupIKScaling(float scaleDifference)
|
||||||
{
|
{
|
||||||
if (avatarVRIK == null) return false;
|
|
||||||
|
|
||||||
_scaleDifference = scaleDifference;
|
_scaleDifference = scaleDifference;
|
||||||
|
|
||||||
VRIKUtils.ApplyScaleToVRIK
|
VRIKUtils.ApplyScaleToVRIK
|
||||||
(
|
(
|
||||||
avatarVRIK,
|
avatarVRIK,
|
||||||
_vrikInitialFootDistance,
|
calibrationData,
|
||||||
_vrikInitialStepThreshold,
|
|
||||||
_vrikInitialStepHeight,
|
|
||||||
_scaleDifference
|
_scaleDifference
|
||||||
);
|
);
|
||||||
|
|
||||||
//VRIKUtils.SetFootsteps
|
|
||||||
//(
|
|
||||||
// avatarVRIK,
|
|
||||||
// _vrikInitialFootPosLeft * _scaleDifference,
|
|
||||||
// _vrikInitialFootPosRight * _scaleDifference,
|
|
||||||
// _vrikInitialFootRotLeft,
|
|
||||||
// _vrikInitialFootRotRight
|
|
||||||
//);
|
|
||||||
|
|
||||||
ResetDesktopVRIK();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnPlayerSetupUpdate(bool isEmotePlaying)
|
public void OnPlayerSetupUpdate(bool isEmotePlaying)
|
||||||
|
@ -367,13 +197,13 @@ internal class DesktopVRIKSystem : MonoBehaviour
|
||||||
|
|
||||||
// Disable tracking completely while emoting
|
// Disable tracking completely while emoting
|
||||||
BodySystem.TrackingEnabled = !isEmotePlaying;
|
BodySystem.TrackingEnabled = !isEmotePlaying;
|
||||||
avatarIKSolver.Reset();
|
IKResetSolver();
|
||||||
ResetDesktopVRIK();
|
ResetDesktopVRIK();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnPlayerSetupSetSitting()
|
public void OnPlayerSetupSetSitting()
|
||||||
{
|
{
|
||||||
avatarIKSolver.Reset();
|
IKResetSolver();
|
||||||
ResetDesktopVRIK();
|
ResetDesktopVRIK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,7 +228,7 @@ internal class DesktopVRIKSystem : MonoBehaviour
|
||||||
if (_movementParent == currentParent)
|
if (_movementParent == currentParent)
|
||||||
{
|
{
|
||||||
// Add platform motion to IK solver
|
// Add platform motion to IK solver
|
||||||
avatarIKSolver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot);
|
cachedSolver.Solver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot);
|
||||||
ResetDesktopVRIK();
|
ResetDesktopVRIK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,80 +236,88 @@ internal class DesktopVRIKSystem : MonoBehaviour
|
||||||
_movementParent = currentParent;
|
_movementParent = currentParent;
|
||||||
_movementPosition = currentPosition;
|
_movementPosition = currentPosition;
|
||||||
_movementRotation = currentRotation;
|
_movementRotation = currentRotation;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not for movementparent, reset ik solver
|
// if not for movementparent, reset ik
|
||||||
avatarIKSolver.Reset();
|
IKResetSolver();
|
||||||
|
IKResetFootsteps();
|
||||||
ResetDesktopVRIK();
|
ResetDesktopVRIK();
|
||||||
//IKResetFootsteps();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnPreSolverUpdate()
|
public void OnPreSolverUpdate()
|
||||||
{
|
{
|
||||||
// Set plant feet
|
// Set plant feet
|
||||||
avatarIKSolver.plantFeet = Setting_PlantFeet;
|
cachedSolver.Solver.plantFeet = DesktopVRIK.EntryPlantFeet.Value;
|
||||||
|
|
||||||
// Apply custom VRIK solving effects
|
// Apply custom VRIK solving effects
|
||||||
IKBodyLeaningOffset(_ikWeightLerp);
|
IKBodyLeaningOffset(_ikWeightLerp);
|
||||||
IKBodyHeadingOffset(_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 (!DesktopVRIK.EntryNetIKPass.Value) return;
|
||||||
if (Setting_BodyLeanWeight <= 0) return;
|
Calibrator.ApplyNetIKPass();
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IKBodyHeadingOffset(float weight)
|
void IKResetSolver()
|
||||||
{
|
{
|
||||||
// Make root heading follow within a set limit
|
cachedSolver.Solver.Reset();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IKResetFootsteps()
|
void IKResetFootsteps()
|
||||||
{
|
{
|
||||||
// Reset footsteps immediatly to initial
|
// Reset footsteps immediatly to initial
|
||||||
if (!Setting_ResetFootsteps) return;
|
if (!DesktopVRIK.EntryResetFootstepsOnIdle.Value) return;
|
||||||
|
|
||||||
VRIKUtils.SetFootsteps
|
VRIKUtils.ResetToInitialFootsteps
|
||||||
(
|
(
|
||||||
avatarVRIK,
|
avatarVRIK,
|
||||||
_vrikInitialFootPosLeft,
|
calibrationData,
|
||||||
_vrikInitialFootPosRight,
|
_scaleDifference
|
||||||
_vrikInitialFootRotLeft,
|
|
||||||
_vrikInitialFootRotRight
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,234 +325,4 @@ internal class DesktopVRIKSystem : MonoBehaviour
|
||||||
{
|
{
|
||||||
_ikSimulatedRootAngle = transform.eulerAngles.y;
|
_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 BTKUILib.UIObjects;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace NAK.DesktopVRIK;
|
namespace NAK.DesktopVRIK.Integrations;
|
||||||
|
|
||||||
public static class BTKUIAddon
|
public static class BTKUIAddon
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using MelonLoader;
|
using MelonLoader;
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace NAK.DesktopVRIK;
|
namespace NAK.DesktopVRIK;
|
||||||
|
|
||||||
|
@ -8,41 +7,44 @@ public class DesktopVRIK : MelonMod
|
||||||
internal static MelonLogger.Instance Logger;
|
internal static MelonLogger.Instance Logger;
|
||||||
internal const string SettingsCategory = nameof(DesktopVRIK);
|
internal const string SettingsCategory = nameof(DesktopVRIK);
|
||||||
|
|
||||||
public static readonly MelonPreferences_Category CategoryDesktopVRIK =
|
public static readonly MelonPreferences_Category Category =
|
||||||
MelonPreferences.CreateCategory(SettingsCategory);
|
MelonPreferences.CreateCategory(SettingsCategory);
|
||||||
|
|
||||||
public static readonly MelonPreferences_Entry<bool> EntryEnabled =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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;
|
public static bool integration_AMT = false;
|
||||||
|
|
||||||
|
@ -50,57 +52,27 @@ public class DesktopVRIK : MelonMod
|
||||||
{
|
{
|
||||||
Logger = LoggerInstance;
|
Logger = LoggerInstance;
|
||||||
|
|
||||||
CategoryDesktopVRIK.Entries.ForEach(e => e.OnEntryValueChangedUntyped.Subscribe(OnUpdateSettings));
|
|
||||||
|
|
||||||
ApplyPatches(typeof(HarmonyPatches.PlayerSetupPatches));
|
|
||||||
|
|
||||||
//BTKUILib Misc Tab
|
//BTKUILib Misc Tab
|
||||||
if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib"))
|
if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "BTKUILib"))
|
||||||
{
|
{
|
||||||
Logger.Msg("Initializing BTKUILib support.");
|
Logger.Msg("Initializing BTKUILib support.");
|
||||||
BTKUIAddon.Init();
|
Integrations.BTKUIAddon.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
//AvatarMotionTweaker Handling
|
//AvatarMotionTweaker Handling
|
||||||
if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "AvatarMotionTweaker"))
|
if (MelonMod.RegisteredMelons.Any(it => it.Info.Name == "AvatarMotionTweaker"))
|
||||||
{
|
{
|
||||||
Logger.Msg("AvatarMotionTweaker was found. Relying on it to handle VRIK locomotion.");
|
|
||||||
integration_AMT = true;
|
integration_AMT = true;
|
||||||
|
Logger.Msg("AvatarMotionTweaker was found. Relying on it to handle VRIK locomotion.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Msg("AvatarMotionTweaker was not found. Using built-in VRIK locomotion handling.");
|
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)
|
void ApplyPatches(Type type)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -26,6 +26,6 @@ using System.Reflection;
|
||||||
namespace NAK.DesktopVRIK.Properties;
|
namespace NAK.DesktopVRIK.Properties;
|
||||||
internal static class AssemblyInfoParams
|
internal static class AssemblyInfoParams
|
||||||
{
|
{
|
||||||
public const string Version = "4.1.8";
|
public const string Version = "4.2.0";
|
||||||
public const string Author = "NotAKidoS";
|
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 RootMotion.FinalIK;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace NAK.DesktopVRIK;
|
namespace NAK.DesktopVRIK.VRIKHelper;
|
||||||
|
|
||||||
public static class VRIKUtils
|
public static class VRIKUtils
|
||||||
{
|
{
|
||||||
public static void ConfigureVRIKReferences(VRIK vrik, bool useVRIKToes)
|
public static void ConfigureVRIKReferences(VRIK vrik, bool useVRIKToes)
|
||||||
{
|
{
|
||||||
//might not work over netik
|
|
||||||
//FixChestAndSpineReferences(vrik);
|
|
||||||
|
|
||||||
if (!useVRIKToes)
|
if (!useVRIKToes)
|
||||||
{
|
{
|
||||||
vrik.references.leftToes = null;
|
vrik.references.leftToes = null;
|
||||||
|
@ -20,36 +17,22 @@ public static class VRIKUtils
|
||||||
FixFingerBonesError(vrik);
|
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)
|
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.leftHand, vrik.solver.leftArm);
|
||||||
FixFingerBones(vrik, vrik.references.rightHand, vrik.solver.rightArm);
|
FixFingerBones(vrik, vrik.references.rightHand, vrik.solver.rightArm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FixFingerBones(VRIK vrik, Transform hand, IKSolverVR.Arm armSolver)
|
public static void CalculateKneeBendNormals(VRIK vrik, ref VRIKCalibrationData calibrationData)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
// Helper function to get position or default to Vector3.zero
|
// Helper function to get position or default to Vector3.zero
|
||||||
Vector3 GetPositionOrDefault(Transform transform) => transform?.position ?? 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.leftCalf),
|
||||||
GetPositionOrDefault(vrik.references.leftFoot)
|
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
|
// Get assumed right knee normal
|
||||||
Vector3[] rightVectors = {
|
Vector3[] rightVectors = {
|
||||||
|
@ -68,10 +51,10 @@ public static class VRIKUtils
|
||||||
GetPositionOrDefault(vrik.references.rightCalf),
|
GetPositionOrDefault(vrik.references.rightCalf),
|
||||||
GetPositionOrDefault(vrik.references.rightFoot)
|
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
|
// 0 uses bendNormalRelToPelvis, 1 is bendNormalRelToTarget
|
||||||
// modifying pelvis normal weight is easier math
|
// modifying pelvis normal weight is easier math
|
||||||
|
@ -79,8 +62,8 @@ public static class VRIKUtils
|
||||||
vrik.solver.rightLeg.bendToTargetWeight = 0f;
|
vrik.solver.rightLeg.bendToTargetWeight = 0f;
|
||||||
|
|
||||||
var pelvis_localRotationInverse = Quaternion.Inverse(vrik.references.pelvis.localRotation);
|
var pelvis_localRotationInverse = Quaternion.Inverse(vrik.references.pelvis.localRotation);
|
||||||
vrik.solver.leftLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * leftKneeNormal;
|
vrik.solver.leftLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * calibrationData.KneeNormalLeft;
|
||||||
vrik.solver.rightLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * rightKneeNormal;
|
vrik.solver.rightLeg.bendNormalRelToPelvis = pelvis_localRotationInverse * calibrationData.KneeNormalRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Vector3 GetNormalFromArray(Vector3[] positions)
|
private static Vector3 GetNormalFromArray(Vector3[] positions)
|
||||||
|
@ -102,17 +85,19 @@ public static class VRIKUtils
|
||||||
return normal.normalized;
|
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
|
// Get distance between feet and thighs
|
||||||
float scaleModifier = Mathf.Max(1f, vrik.references.pelvis.lossyScale.x);
|
float scaleModifier = Mathf.Max(1f, vrik.references.pelvis.lossyScale.x);
|
||||||
float footDistance = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.rightFoot.position);
|
float footDistance = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.rightFoot.position);
|
||||||
initialFootDistance = footDistance * 0.5f;
|
|
||||||
initialStepThreshold = footDistance * scaleModifier;
|
calibrationData.InitialFootDistance = footDistance * 0.5f;
|
||||||
initialStepHeight = Vector3.Distance(vrik.references.leftFoot.position, vrik.references.leftCalf.position) * 0.2f;
|
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 root = vrik.references.root;
|
||||||
Transform leftFoot = vrik.references.leftFoot;
|
Transform leftFoot = vrik.references.leftFoot;
|
||||||
|
@ -122,13 +107,13 @@ public static class VRIKUtils
|
||||||
Quaternion rootWorldRot = root.rotation;
|
Quaternion rootWorldRot = root.rotation;
|
||||||
|
|
||||||
// Calculate the world rotation of the left and right feet relative to the root bone
|
// Calculate the world rotation of the left and right feet relative to the root bone
|
||||||
initialFootPosLeft = root.InverseTransformPoint(leftFoot.position);
|
calibrationData.InitialFootPosLeft = root.parent.InverseTransformPoint(leftFoot.position);
|
||||||
initialFootPosRight = root.InverseTransformPoint(rightFoot.position);
|
calibrationData.InitialFootPosRight = root.parent.InverseTransformPoint(rightFoot.position);
|
||||||
initialFootRotLeft = Quaternion.Inverse(rootWorldRot) * leftFoot.rotation;
|
calibrationData.InitialFootRotLeft = Quaternion.Inverse(rootWorldRot) * leftFoot.rotation;
|
||||||
initialFootRotRight = Quaternion.Inverse(rootWorldRot) * rightFoot.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 locomotionSolver = vrik.solver.locomotion;
|
||||||
|
|
||||||
|
@ -138,9 +123,10 @@ public static class VRIKUtils
|
||||||
|
|
||||||
var root = vrik.references.root;
|
var root = vrik.references.root;
|
||||||
var rootWorldRot = vrik.references.root.rotation;
|
var rootWorldRot = vrik.references.root.rotation;
|
||||||
|
|
||||||
// hack, use parent transform instead as setting feet position moves root
|
// hack, use parent transform instead as setting feet position moves root
|
||||||
footstepLeft.Reset(rootWorldRot, root.parent.TransformPoint(footPosLeft), rootWorldRot * footRotLeft);
|
footstepLeft.Reset(rootWorldRot, root.parent.TransformPoint(calibrationData.InitialFootPosLeft * scaleModifier), rootWorldRot * calibrationData.InitialFootRotLeft);
|
||||||
footstepRight.Reset(rootWorldRot, root.parent.TransformPoint(footPosRight), rootWorldRot * footRotRight);
|
footstepRight.Reset(rootWorldRot, root.parent.TransformPoint(calibrationData.InitialFootPosRight * scaleModifier), rootWorldRot * calibrationData.InitialFootRotRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetupHeadIKTarget(VRIK vrik)
|
public static void SetupHeadIKTarget(VRIK vrik)
|
||||||
|
@ -155,15 +141,15 @@ public static class VRIKUtils
|
||||||
vrik.solver.spine.headTarget.localRotation = Quaternion.identity;
|
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;
|
var locomotionSolver = vrik.solver.locomotion;
|
||||||
locomotionSolver.footDistance = footDistance * modifier;
|
locomotionSolver.footDistance = calibrationData.InitialFootDistance * scaleModifier;
|
||||||
locomotionSolver.stepThreshold = stepThreshold * modifier;
|
locomotionSolver.stepThreshold = calibrationData.InitialStepThreshold * scaleModifier;
|
||||||
ScaleStepHeight(locomotionSolver.stepHeight, stepHeight * modifier);
|
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;
|
Keyframe[] keyframes = stepHeightCurve.keys;
|
||||||
keyframes[1].value = mag;
|
keyframes[1].value = mag;
|
Loading…
Add table
Add a link
Reference in a new issue