mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-02 22:39:22 +00:00
[AlternateIKSystem] Add halfbody support.
This commit is contained in:
parent
cd34aebeb0
commit
69b84775ec
5 changed files with 143 additions and 131 deletions
|
@ -1,12 +1,13 @@
|
||||||
using RootMotion.FinalIK;
|
using RootMotion.FinalIK;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using Valve.VR;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
namespace NAK.AlternateIKSystem.IK;
|
namespace NAK.AlternateIKSystem.IK;
|
||||||
|
|
||||||
internal static class IKCalibrator
|
internal static class IKCalibrator
|
||||||
{
|
{
|
||||||
#region VRIK Setup
|
#region VRIK Solver Setup
|
||||||
|
|
||||||
public static VRIK SetupVrIk(Animator animator)
|
public static VRIK SetupVrIk(Animator animator)
|
||||||
{
|
{
|
||||||
|
@ -183,14 +184,39 @@ internal static class IKCalibrator
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// TODO: figure out proper Desktop & VR organization
|
#region VRIK Calibration
|
||||||
public static void SetupHeadIKTargetDesktop(VRIK vrik)
|
|
||||||
|
public static void SetupHeadIKTarget(VRIK vrik, Transform parent = null)
|
||||||
{
|
{
|
||||||
|
// VR Camera may have Head IK Target from previous avatar
|
||||||
|
Transform existingTarget = parent?.Find("Head IK Target");
|
||||||
|
if (existingTarget != null)
|
||||||
|
Object.DestroyImmediate(existingTarget.gameObject);
|
||||||
|
|
||||||
|
parent ??= vrik.references.head;
|
||||||
|
|
||||||
// Lazy HeadIKTarget calibration
|
// Lazy HeadIKTarget calibration
|
||||||
if (vrik.solver.spine.headTarget == null)
|
vrik.solver.spine.headTarget = new GameObject("Head IK Target").transform;
|
||||||
vrik.solver.spine.headTarget = new GameObject("Head IK Target").transform;
|
|
||||||
vrik.solver.spine.headTarget.parent = vrik.references.head;
|
|
||||||
vrik.solver.spine.headTarget.localPosition = Vector3.zero;
|
|
||||||
vrik.solver.spine.headTarget.localRotation = Quaternion.identity;
|
vrik.solver.spine.headTarget.localRotation = Quaternion.identity;
|
||||||
|
|
||||||
|
vrik.solver.spine.headTarget.parent = parent;
|
||||||
|
vrik.solver.spine.headTarget.localPosition = Vector3.zero;
|
||||||
|
vrik.solver.spine.headTarget.localScale = Vector3.one;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetupHandIKTarget(VRIK vrik, Transform handOffset, Transform handAnchor, bool isLeft)
|
||||||
|
{
|
||||||
|
handAnchor.SetParent(isLeft ? vrik.references.leftHand : vrik.references.rightHand);
|
||||||
|
handAnchor.localPosition = Vector3.zero;
|
||||||
|
handAnchor.localRotation = Quaternion.identity;
|
||||||
|
handAnchor.SetParent(handOffset, true);
|
||||||
|
handAnchor.localPosition = Vector3.zero;
|
||||||
|
|
||||||
|
if (isLeft)
|
||||||
|
vrik.solver.leftArm.target = handAnchor;
|
||||||
|
else
|
||||||
|
vrik.solver.rightArm.target = handAnchor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
|
@ -41,9 +41,34 @@ internal abstract class IKHandler
|
||||||
|
|
||||||
public virtual void OnInitializeIk() { }
|
public virtual void OnInitializeIk() { }
|
||||||
|
|
||||||
public virtual void OnPlayerScaled(float scaleDifference) { }
|
public virtual void OnPlayerScaled(float scaleDifference)
|
||||||
|
{
|
||||||
|
VRIKUtils.ApplyScaleToVRIK
|
||||||
|
(
|
||||||
|
_vrik,
|
||||||
|
_locomotionData,
|
||||||
|
_scaleDifference = scaleDifference
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void OnPlayerHandleMovementParent(CVRMovementParent currentParent) { }
|
public virtual void OnPlayerHandleMovementParent(CVRMovementParent currentParent, Vector3 platformPivot)
|
||||||
|
{
|
||||||
|
Vector3 currentPosition = currentParent._referencePoint.position;
|
||||||
|
Quaternion currentRotation = Quaternion.Euler(0f, currentParent.transform.rotation.eulerAngles.y, 0f);
|
||||||
|
|
||||||
|
Vector3 deltaPosition = currentPosition - _movementPosition;
|
||||||
|
Quaternion deltaRotation = Quaternion.Inverse(_movementRotation) * currentRotation;
|
||||||
|
|
||||||
|
if (_movementParent == currentParent)
|
||||||
|
{
|
||||||
|
_solver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot);
|
||||||
|
_ikSimulatedRootAngle = Mathf.Repeat(_ikSimulatedRootAngle + deltaRotation.eulerAngles.y, 360f);
|
||||||
|
}
|
||||||
|
|
||||||
|
_movementParent = currentParent;
|
||||||
|
_movementPosition = currentPosition;
|
||||||
|
_movementRotation = currentRotation;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
@ -29,42 +29,6 @@ internal class IKHandlerDesktop : IKHandler
|
||||||
_vrik.onPreSolverUpdate.AddListener(OnPreSolverUpdateDesktop);
|
_vrik.onPreSolverUpdate.AddListener(OnPreSolverUpdateDesktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnPlayerScaled(float scaleDifference)
|
|
||||||
{
|
|
||||||
VRIKUtils.ApplyScaleToVRIK
|
|
||||||
(
|
|
||||||
_vrik,
|
|
||||||
_locomotionData,
|
|
||||||
_scaleDifference = scaleDifference
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnPlayerHandleMovementParent(CVRMovementParent currentParent)
|
|
||||||
{
|
|
||||||
// Get current position
|
|
||||||
Vector3 currentPosition = currentParent._referencePoint.position;
|
|
||||||
Quaternion currentRotation = Quaternion.Euler(0f, currentParent.transform.rotation.eulerAngles.y, 0f);
|
|
||||||
|
|
||||||
// Convert to delta position (how much changed since last frame)
|
|
||||||
Vector3 deltaPosition = currentPosition - _movementPosition;
|
|
||||||
Quaternion deltaRotation = Quaternion.Inverse(_movementRotation) * currentRotation;
|
|
||||||
|
|
||||||
// Desktop pivots from playerlocal transform
|
|
||||||
Vector3 platformPivot = IKManager.Instance.transform.position;
|
|
||||||
|
|
||||||
// Prevent targeting other parent position
|
|
||||||
if (_movementParent == currentParent)
|
|
||||||
{
|
|
||||||
_solver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot);
|
|
||||||
_ikSimulatedRootAngle = Mathf.Repeat(_ikSimulatedRootAngle + deltaRotation.eulerAngles.y, 360f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store for next frame
|
|
||||||
_movementParent = currentParent;
|
|
||||||
_movementPosition = currentPosition;
|
|
||||||
_movementRotation = currentRotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Weight Overrides
|
#region Weight Overrides
|
||||||
|
@ -81,57 +45,6 @@ internal class IKHandlerDesktop : IKHandler
|
||||||
_solver.spine.positionWeight = 0f;
|
_solver.spine.positionWeight = 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update_HeadWeight()
|
|
||||||
{
|
|
||||||
float targetWeight = GetTargetWeight(BodyControl.TrackingHead, true);
|
|
||||||
BodyControl.SetHeadWeight(_solver.spine, targetWeight);
|
|
||||||
BodyControl.SetLookAtWeight(IKManager.lookAtIk, targetWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update_LeftArmWeight()
|
|
||||||
{
|
|
||||||
float leftArmWeight = GetTargetWeight(BodyControl.TrackingLeftArm, _solver.leftArm.target != null);
|
|
||||||
BodyControl.SetArmWeight(_solver.leftArm, leftArmWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update_RightArmWeight()
|
|
||||||
{
|
|
||||||
float rightArmWeight = GetTargetWeight(BodyControl.TrackingRightArm, _solver.rightArm.target != null);
|
|
||||||
BodyControl.SetArmWeight(_solver.rightArm, rightArmWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update_LeftLegWeight()
|
|
||||||
{
|
|
||||||
float leftLegWeight = GetTargetWeight(BodyControl.TrackingLeftLeg, _solver.leftLeg.target != null);
|
|
||||||
BodyControl.SetLegWeight(_solver.leftLeg, leftLegWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update_RightLegWeight()
|
|
||||||
{
|
|
||||||
float rightLegWeight = GetTargetWeight(BodyControl.TrackingRightLeg, _solver.rightLeg.target != null);
|
|
||||||
BodyControl.SetLegWeight(_solver.rightLeg, rightLegWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update_PelvisWeight()
|
|
||||||
{
|
|
||||||
float pelvisWeight = GetTargetWeight(BodyControl.TrackingPelvis, _solver.spine.pelvisTarget != null);
|
|
||||||
BodyControl.SetPelvisWeight(_solver.spine, pelvisWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update_LocomotionWeight()
|
|
||||||
{
|
|
||||||
_locomotionWeight = Mathf.Lerp(_locomotionWeight, BodyControl.TrackingLocomotion ? 1f : 0f,
|
|
||||||
Time.deltaTime * ModSettings.EntryIKLerpSpeed.Value * 2f);
|
|
||||||
BodyControl.SetLocomotionWeight(_solver.locomotion, _locomotionWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update_IKPositionWeight()
|
|
||||||
{
|
|
||||||
float ikPositionWeight = BodyControl.TrackingAll ? BodyControl.TrackingIKPositionWeight : 0f;
|
|
||||||
BodyControl.SetIKPositionWeight(_solver, ikPositionWeight);
|
|
||||||
BodyControl.SetIKPositionWeight(IKManager.lookAtIk, ikPositionWeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region VRIK Solver Events
|
#region VRIK Solver Events
|
||||||
|
|
|
@ -25,42 +25,33 @@ internal class IKHandlerHalfBody : IKHandler
|
||||||
shouldTrackRightLeg = false;
|
shouldTrackRightLeg = false;
|
||||||
shouldTrackPelvis = false;
|
shouldTrackPelvis = false;
|
||||||
shouldTrackLocomotion = true;
|
shouldTrackLocomotion = true;
|
||||||
|
|
||||||
|
_vrik.onPreSolverUpdate.AddListener(OnPreSolverUpdateHalfBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public override void OnPlayerScaled(float scaleDifference)
|
#region VRIK Solver Events
|
||||||
|
|
||||||
|
private void OnPreSolverUpdateHalfBody()
|
||||||
{
|
{
|
||||||
VRIKUtils.ApplyScaleToVRIK
|
_solver.plantFeet = ModSettings.EntryPlantFeet.Value;
|
||||||
(
|
|
||||||
_vrik,
|
|
||||||
_locomotionData,
|
|
||||||
_scaleDifference = scaleDifference
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnPlayerHandleMovementParent(CVRMovementParent currentParent)
|
// Make root heading follow within a set limit
|
||||||
{
|
if (ModSettings.EntryBodyHeadingLimit.Value > 0)
|
||||||
// Get current position
|
|
||||||
Vector3 currentPosition = currentParent._referencePoint.position;
|
|
||||||
Quaternion currentRotation = Quaternion.Euler(0f, currentParent.transform.rotation.eulerAngles.y, 0f);
|
|
||||||
|
|
||||||
// Convert to delta position (how much changed since last frame)
|
|
||||||
Vector3 deltaPosition = currentPosition - _movementPosition;
|
|
||||||
Quaternion deltaRotation = Quaternion.Inverse(_movementRotation) * currentRotation;
|
|
||||||
|
|
||||||
// Desktop pivots from playerlocal transform
|
|
||||||
Vector3 platformPivot = IKManager.Instance.transform.position;
|
|
||||||
|
|
||||||
// Prevent targeting other parent position
|
|
||||||
if (_movementParent == currentParent)
|
|
||||||
{
|
{
|
||||||
_solver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot);
|
float weightedAngleLimit = ModSettings.EntryBodyHeadingLimit.Value * _solver.locomotion.weight;
|
||||||
_ikSimulatedRootAngle = Mathf.Repeat(_ikSimulatedRootAngle + deltaRotation.eulerAngles.y, 360f);
|
float currentRotation = IKManager.Instance.GetPlayerRotation().y;
|
||||||
}
|
float deltaAngleRoot = Mathf.DeltaAngle(currentRotation, _ikSimulatedRootAngle);
|
||||||
|
|
||||||
// Store for next frame
|
if (Mathf.Abs(deltaAngleRoot) > weightedAngleLimit)
|
||||||
_movementParent = currentParent;
|
{
|
||||||
_movementPosition = currentPosition;
|
deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit;
|
||||||
_movementRotation = currentRotation;
|
_ikSimulatedRootAngle = Mathf.MoveTowardsAngle(_ikSimulatedRootAngle, currentRotation, Mathf.Abs(deltaAngleRoot) - weightedAngleLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
_solver.spine.rootHeadingOffset = deltaAngleRoot;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -6,6 +6,7 @@ using NAK.AlternateIKSystem.VRIKHelpers;
|
||||||
using RootMotion.FinalIK;
|
using RootMotion.FinalIK;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.Events;
|
using UnityEngine.Events;
|
||||||
|
using Object = System.Object;
|
||||||
|
|
||||||
namespace NAK.AlternateIKSystem.IK;
|
namespace NAK.AlternateIKSystem.IK;
|
||||||
|
|
||||||
|
@ -32,6 +33,18 @@ public class IKManager : MonoBehaviour
|
||||||
internal Transform _desktopCamera;
|
internal Transform _desktopCamera;
|
||||||
internal Transform _vrCamera;
|
internal Transform _vrCamera;
|
||||||
|
|
||||||
|
// Controller Info
|
||||||
|
private Transform _leftController;
|
||||||
|
private Transform _rightController;
|
||||||
|
private Transform _leftHandTarget;
|
||||||
|
private Transform _leftHandRotations;
|
||||||
|
private Transform _rightHandTarget;
|
||||||
|
private Transform _rightHandRotations;
|
||||||
|
|
||||||
|
// Hand Anchor Offsets
|
||||||
|
private Vector3 _handAnchorPositionOffset = new Vector3(-0.038f, 0.0389f, -0.138f);
|
||||||
|
private Vector3 _handAnchorRotationOffset = Vector3.zero;
|
||||||
|
|
||||||
// Avatar Info
|
// Avatar Info
|
||||||
private Animator _animator;
|
private Animator _animator;
|
||||||
private Transform _hipTransform;
|
private Transform _hipTransform;
|
||||||
|
@ -39,6 +52,8 @@ public class IKManager : MonoBehaviour
|
||||||
// Animator Info
|
// Animator Info
|
||||||
private int _animLocomotionLayer = -1;
|
private int _animLocomotionLayer = -1;
|
||||||
private int _animIKPoseLayer = -1;
|
private int _animIKPoseLayer = -1;
|
||||||
|
private const string _locomotionLayerName = "Locomotion/Emotes";
|
||||||
|
private const string _ikposeLayerName = "IKPose";
|
||||||
|
|
||||||
// Pose Info
|
// Pose Info
|
||||||
private HumanPoseHandler _humanPoseHandler;
|
private HumanPoseHandler _humanPoseHandler;
|
||||||
|
@ -60,8 +75,16 @@ public class IKManager : MonoBehaviour
|
||||||
|
|
||||||
_desktopCamera = PlayerSetup.Instance.desktopCamera.transform;
|
_desktopCamera = PlayerSetup.Instance.desktopCamera.transform;
|
||||||
_vrCamera = PlayerSetup.Instance.vrCamera.transform;
|
_vrCamera = PlayerSetup.Instance.vrCamera.transform;
|
||||||
}
|
_leftController = PlayerSetup.Instance.vrLeftHandTracker.transform;
|
||||||
|
_rightController = PlayerSetup.Instance.vrRightHandTracker.transform;
|
||||||
|
|
||||||
|
// ouchie
|
||||||
|
_leftHandTarget = _leftController.Find("LeftHandTarget");
|
||||||
|
_leftHandRotations = _leftHandTarget.Find("LeftHandRotations");
|
||||||
|
_rightHandTarget = _rightController.Find("RightHandTarget");
|
||||||
|
_rightHandRotations = _rightHandTarget.Find("RightHandRotations");
|
||||||
|
}
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
BodyControl.Update();
|
BodyControl.Update();
|
||||||
|
@ -91,8 +114,8 @@ public class IKManager : MonoBehaviour
|
||||||
|
|
||||||
_animator.cullingMode = AnimatorCullingMode.AlwaysAnimate;
|
_animator.cullingMode = AnimatorCullingMode.AlwaysAnimate;
|
||||||
|
|
||||||
_animIKPoseLayer = _animator.GetLayerIndex("IKPose");
|
_animIKPoseLayer = _animator.GetLayerIndex(_ikposeLayerName);
|
||||||
_animLocomotionLayer = _animator.GetLayerIndex("Locomotion/Emotes");
|
_animLocomotionLayer = _animator.GetLayerIndex(_locomotionLayerName);
|
||||||
|
|
||||||
_hipTransform = _animator.GetBoneTransform(HumanBodyBones.Hips);
|
_hipTransform = _animator.GetBoneTransform(HumanBodyBones.Hips);
|
||||||
|
|
||||||
|
@ -160,7 +183,7 @@ public class IKManager : MonoBehaviour
|
||||||
if (!_isAvatarInitialized)
|
if (!_isAvatarInitialized)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_ikHandler?.OnPlayerHandleMovementParent(movementParent);
|
_ikHandler?.OnPlayerHandleMovementParent(movementParent, GetPlayerPosition());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +207,7 @@ public class IKManager : MonoBehaviour
|
||||||
IKCalibrator.ConfigureDesktopVrIk(_vrik);
|
IKCalibrator.ConfigureDesktopVrIk(_vrik);
|
||||||
_ikHandler = new IKHandlerDesktop(_vrik);
|
_ikHandler = new IKHandlerDesktop(_vrik);
|
||||||
|
|
||||||
IKCalibrator.SetupHeadIKTargetDesktop(_vrik);
|
IKCalibrator.SetupHeadIKTarget(_vrik);
|
||||||
|
|
||||||
InitializeIkGeneral();
|
InitializeIkGeneral();
|
||||||
|
|
||||||
|
@ -197,7 +220,17 @@ public class IKManager : MonoBehaviour
|
||||||
|
|
||||||
IKCalibrator.ConfigureHalfBodyVrIk(_vrik);
|
IKCalibrator.ConfigureHalfBodyVrIk(_vrik);
|
||||||
_ikHandler = new IKHandlerHalfBody(_vrik);
|
_ikHandler = new IKHandlerHalfBody(_vrik);
|
||||||
|
|
||||||
|
IKCalibrator.SetupHeadIKTarget(_vrik, _vrCamera);
|
||||||
|
IKCalibrator.SetupHandIKTarget(_vrik, _leftHandTarget, _leftHandRotations, true);
|
||||||
|
IKCalibrator.SetupHandIKTarget(_vrik, _rightHandTarget, _rightHandRotations, false);
|
||||||
|
|
||||||
|
// Configure controller offsets
|
||||||
|
_leftHandTarget.localPosition = _handAnchorPositionOffset;
|
||||||
|
_leftHandTarget.localEulerAngles = _handAnchorRotationOffset;
|
||||||
|
_rightHandTarget.localPosition = Vector3.Scale(_handAnchorPositionOffset, new Vector3(-1, 1, 1));
|
||||||
|
_rightHandTarget.localEulerAngles = Vector3.Scale(_handAnchorRotationOffset, new Vector3(1, -1, -1));
|
||||||
|
|
||||||
InitializeIkGeneral();
|
InitializeIkGeneral();
|
||||||
|
|
||||||
_ikHandler.OnInitializeIk();
|
_ikHandler.OnInitializeIk();
|
||||||
|
@ -226,6 +259,30 @@ public class IKManager : MonoBehaviour
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Public Methods
|
||||||
|
|
||||||
|
public Vector3 GetPlayerPosition()
|
||||||
|
{
|
||||||
|
if (!MetaPort.Instance.isUsingVr)
|
||||||
|
return transform.position;
|
||||||
|
|
||||||
|
Vector3 vrPosition = _vrCamera.transform.position;
|
||||||
|
vrPosition.y = transform.position.y;
|
||||||
|
return vrPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Quaternion GetPlayerRotation()
|
||||||
|
{
|
||||||
|
if (!MetaPort.Instance.isUsingVr)
|
||||||
|
return transform.rotation;
|
||||||
|
|
||||||
|
Vector3 vrForward = _vrCamera.transform.forward;
|
||||||
|
vrForward.y = 0f;
|
||||||
|
return Quaternion.LookRotation(vrForward, Vector3.up);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region VRIK Solver Events General
|
#region VRIK Solver Events General
|
||||||
|
|
||||||
private void OnPreSolverUpdateGeneral()
|
private void OnPreSolverUpdateGeneral()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue