mirror of
https://github.com/NotAKidoS/NAK_CVR_Mods.git
synced 2025-09-02 06:19:22 +00:00
Partially rewrote everything so it is cleaner, does not need Traverse/Reflection, and no longer piggybacks on the game handling VRIK on Desktop for whatever reason. This version also handles VRIK Locomotion weight standalone instead of requiring AvatarMotionTweaker, but if AMT is found it will rely on it anyways. This can be overwridden in the melonprefs, but its still gonna be double the maths for no reason.
646 lines
20 KiB
C#
646 lines
20 KiB
C#
using ABI.CCK.Components;
|
|
using ABI_RC.Core.Base;
|
|
using ABI_RC.Core.Player;
|
|
using ABI_RC.Systems.IK;
|
|
using ABI_RC.Systems.IK.SubSystems;
|
|
using ABI_RC.Systems.MovementSystem;
|
|
using RootMotion.FinalIK;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
|
|
namespace NAK.Melons.DesktopVRIK;
|
|
|
|
internal class DesktopVRIKSystem : MonoBehaviour
|
|
{
|
|
public static DesktopVRIKSystem Instance;
|
|
public static Dictionary<HumanBodyBones, bool> BoneExists;
|
|
public static readonly float[] IKPoseMuscles = new float[]
|
|
{
|
|
0.00133321f,
|
|
8.195831E-06f,
|
|
8.537738E-07f,
|
|
-0.002669832f,
|
|
-7.651234E-06f,
|
|
-0.001659694f,
|
|
0f,
|
|
0f,
|
|
0f,
|
|
0.04213953f,
|
|
0.0003007996f,
|
|
-0.008032114f,
|
|
-0.03059979f,
|
|
-0.0003182998f,
|
|
0.009640567f,
|
|
0f,
|
|
0f,
|
|
0f,
|
|
0f,
|
|
0f,
|
|
0f,
|
|
0.5768794f,
|
|
0.01061097f,
|
|
-0.1127839f,
|
|
0.9705755f,
|
|
0.07972051f,
|
|
-0.0268422f,
|
|
0.007237188f,
|
|
0f,
|
|
0.5768792f,
|
|
0.01056608f,
|
|
-0.1127519f,
|
|
0.9705756f,
|
|
0.07971933f,
|
|
-0.02682396f,
|
|
0.007229362f,
|
|
0f,
|
|
-5.651802E-06f,
|
|
-3.034899E-07f,
|
|
0.4100508f,
|
|
0.3610304f,
|
|
-0.0838329f,
|
|
0.9262537f,
|
|
0.1353517f,
|
|
-0.03578902f,
|
|
0.06005657f,
|
|
-4.95989E-06f,
|
|
-1.43007E-06f,
|
|
0.4096187f,
|
|
0.363263f,
|
|
-0.08205152f,
|
|
0.9250782f,
|
|
0.1345718f,
|
|
-0.03572125f,
|
|
0.06055461f,
|
|
-1.079177f,
|
|
0.2095419f,
|
|
0.6140652f,
|
|
0.6365265f,
|
|
0.6683931f,
|
|
-0.4764312f,
|
|
0.8099416f,
|
|
0.8099371f,
|
|
0.6658203f,
|
|
-0.7327053f,
|
|
0.8113618f,
|
|
0.8114051f,
|
|
0.6643661f,
|
|
-0.40341f,
|
|
0.8111364f,
|
|
0.8111367f,
|
|
0.6170399f,
|
|
-0.2524227f,
|
|
0.8138723f,
|
|
0.8110135f,
|
|
-1.079171f,
|
|
0.2095456f,
|
|
0.6140658f,
|
|
0.6365255f,
|
|
0.6683878f,
|
|
-0.4764301f,
|
|
0.8099402f,
|
|
0.8099376f,
|
|
0.6658241f,
|
|
-0.7327023f,
|
|
0.8113653f,
|
|
0.8113793f,
|
|
0.664364f,
|
|
-0.4034042f,
|
|
0.811136f,
|
|
0.8111364f,
|
|
0.6170469f,
|
|
-0.2524345f,
|
|
0.8138595f,
|
|
0.8110138f
|
|
};
|
|
enum AvatarPose
|
|
{
|
|
Default = 0,
|
|
Initial = 1,
|
|
IKPose = 2,
|
|
TPose = 3
|
|
}
|
|
|
|
// ChilloutVR Player Components
|
|
private PlayerSetup playerSetup;
|
|
private MovementSystem movementSystem;
|
|
|
|
// DesktopVRIK Settings
|
|
public bool Setting_Enabled = true;
|
|
public bool Setting_PlantFeet = true;
|
|
public float Setting_BodyLeanWeight;
|
|
public float Setting_BodyHeadingLimit;
|
|
public float Setting_PelvisHeadingWeight;
|
|
public float Setting_ChestHeadingWeight;
|
|
|
|
// Calibration Settings
|
|
public bool Setting_UseVRIKToes = true;
|
|
public bool Setting_FindUnmappedToes = true;
|
|
|
|
// Integration Settings
|
|
public bool Setting_IntegrationAMT = false;
|
|
|
|
// Avatar Components
|
|
public CVRAvatar avatarDescriptor = null;
|
|
public Animator avatarAnimator = null;
|
|
public Transform avatarTransform = null;
|
|
public LookAtIK avatarLookAtIK = null;
|
|
public VRIK avatarVRIK = null;
|
|
public IKSolverVR avatarIKSolver = null;
|
|
|
|
// Calibration Objects
|
|
public HumanPose HumanPose;
|
|
public HumanPose InitialHumanPose;
|
|
public HumanPoseHandler HumanPoseHandler;
|
|
|
|
// Animator Info
|
|
public int locomotionLayer = -1;
|
|
public int customIKPoseLayer = -1;
|
|
public bool requireFixTransforms = false;
|
|
|
|
// VRIK Calibration Info
|
|
public Vector3 leftKneeNormal;
|
|
public Vector3 rightKneeNormal;
|
|
public float initialFootDistance;
|
|
public float initialStepThreshold;
|
|
public float initialStepHeight;
|
|
|
|
// Player Info
|
|
private Transform _cameraTransform;
|
|
private bool _isEmotePlaying;
|
|
private float _simulatedRootAngle;
|
|
|
|
// Last Movement Parent Info
|
|
private Vector3 _previousPosition;
|
|
private Quaternion _previousRotation;
|
|
|
|
DesktopVRIKSystem()
|
|
{
|
|
BoneExists = new Dictionary<HumanBodyBones, bool>();
|
|
}
|
|
|
|
void Start()
|
|
{
|
|
Instance = this;
|
|
|
|
playerSetup = GetComponent<PlayerSetup>();
|
|
movementSystem = GetComponent<MovementSystem>();
|
|
|
|
_cameraTransform = playerSetup.desktopCamera.transform;
|
|
|
|
DesktopVRIKMod.UpdateAllSettings();
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if (avatarVRIK == null) return;
|
|
|
|
HandleLocomotionTracking();
|
|
ApplyBodySystemWeights();
|
|
}
|
|
|
|
void HandleLocomotionTracking()
|
|
{
|
|
bool isMoving = movementSystem.movementVector.magnitude > 0f;
|
|
|
|
// AvatarMotionTweaker handles VRIK a bit better than DesktopVRIK
|
|
if (Setting_IntegrationAMT && DesktopVRIKMod.integration_AMT)
|
|
{
|
|
if (isMoving)
|
|
{
|
|
if (BodySystem.TrackingLocomotionEnabled)
|
|
{
|
|
BodySystem.TrackingLocomotionEnabled = false;
|
|
avatarIKSolver.Reset();
|
|
ResetDesktopVRIK();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!BodySystem.TrackingLocomotionEnabled)
|
|
{
|
|
BodySystem.TrackingLocomotionEnabled = true;
|
|
avatarIKSolver.Reset();
|
|
ResetDesktopVRIK();
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
bool isGrounded = movementSystem._isGrounded;
|
|
bool isCrouching = movementSystem.crouching;
|
|
bool isProne = movementSystem.prone;
|
|
bool isFlying = movementSystem.flying;
|
|
|
|
// Why do it myself if VRIK already does the maths
|
|
Vector3 headLocalPos = avatarIKSolver.spine.headPosition - avatarIKSolver.spine.rootPosition;
|
|
float upright = 1f + (headLocalPos.y - avatarIKSolver.spine.headHeight);
|
|
|
|
if (isMoving || isCrouching || isProne || isFlying || !isGrounded)
|
|
{
|
|
if (BodySystem.TrackingLocomotionEnabled)
|
|
{
|
|
BodySystem.TrackingLocomotionEnabled = false;
|
|
avatarIKSolver.Reset();
|
|
ResetDesktopVRIK();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!BodySystem.TrackingLocomotionEnabled && upright > 0.8f)
|
|
{
|
|
BodySystem.TrackingLocomotionEnabled = true;
|
|
avatarIKSolver.Reset();
|
|
ResetDesktopVRIK();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ApplyBodySystemWeights()
|
|
{
|
|
void SetArmWeight(IKSolverVR.Arm arm, bool isTracked)
|
|
{
|
|
arm.positionWeight = isTracked ? 1f : 0f;
|
|
arm.rotationWeight = isTracked ? 1f : 0f;
|
|
arm.shoulderRotationWeight = isTracked ? 1f : 0f;
|
|
arm.shoulderTwistWeight = isTracked ? 1f : 0f;
|
|
}
|
|
void SetLegWeight(IKSolverVR.Leg leg, bool isTracked)
|
|
{
|
|
leg.positionWeight = isTracked ? 1f : 0f;
|
|
leg.rotationWeight = isTracked ? 1f : 0f;
|
|
}
|
|
if (BodySystem.TrackingEnabled)
|
|
{
|
|
avatarVRIK.enabled = true;
|
|
avatarIKSolver.IKPositionWeight = BodySystem.TrackingPositionWeight;
|
|
avatarIKSolver.locomotion.weight = BodySystem.TrackingLocomotionEnabled ? 1f : 0f;
|
|
|
|
SetArmWeight(avatarIKSolver.leftArm, BodySystem.TrackingLeftArmEnabled && avatarIKSolver.leftArm.target != null);
|
|
SetArmWeight(avatarIKSolver.rightArm, BodySystem.TrackingRightArmEnabled && avatarIKSolver.rightArm.target != null);
|
|
SetLegWeight(avatarIKSolver.leftLeg, BodySystem.TrackingLeftLegEnabled && avatarIKSolver.leftLeg.target != null);
|
|
SetLegWeight(avatarIKSolver.rightLeg, BodySystem.TrackingRightLegEnabled && avatarIKSolver.rightLeg.target != null);
|
|
}
|
|
else
|
|
{
|
|
avatarVRIK.enabled = false;
|
|
avatarIKSolver.IKPositionWeight = 0f;
|
|
avatarIKSolver.locomotion.weight = 0f;
|
|
|
|
SetArmWeight(avatarIKSolver.leftArm, false);
|
|
SetArmWeight(avatarIKSolver.rightArm, false);
|
|
SetLegWeight(avatarIKSolver.leftLeg, false);
|
|
SetLegWeight(avatarIKSolver.rightLeg, false);
|
|
}
|
|
}
|
|
|
|
public void OnSetupAvatarDesktop()
|
|
{
|
|
if (!Setting_Enabled) return;
|
|
|
|
CalibrateDesktopVRIK();
|
|
ResetDesktopVRIK();
|
|
}
|
|
|
|
public bool OnSetupIKScaling(float scaleDifference)
|
|
{
|
|
if (avatarVRIK == null) return false;
|
|
|
|
VRIKUtils.ApplyScaleToVRIK
|
|
(
|
|
avatarVRIK,
|
|
initialFootDistance,
|
|
initialStepThreshold,
|
|
initialStepHeight,
|
|
scaleDifference
|
|
);
|
|
|
|
avatarIKSolver.Reset();
|
|
ResetDesktopVRIK();
|
|
return true;
|
|
}
|
|
|
|
public void OnPlayerSetupUpdate(bool isEmotePlaying)
|
|
{
|
|
if (avatarVRIK == null) return;
|
|
|
|
bool changed = isEmotePlaying != _isEmotePlaying;
|
|
if (!changed) return;
|
|
|
|
_isEmotePlaying = isEmotePlaying;
|
|
|
|
avatarTransform.localPosition = Vector3.zero;
|
|
avatarTransform.localRotation = Quaternion.identity;
|
|
|
|
if (avatarLookAtIK != null)
|
|
avatarLookAtIK.enabled = !isEmotePlaying;
|
|
|
|
BodySystem.TrackingEnabled = !isEmotePlaying;
|
|
|
|
avatarIKSolver.Reset();
|
|
ResetDesktopVRIK();
|
|
}
|
|
|
|
public bool OnPlayerSetupResetIk()
|
|
{
|
|
if (avatarVRIK == null) return false;
|
|
|
|
CVRMovementParent currentParent = movementSystem._currentParent;
|
|
if (currentParent == null) return false;
|
|
|
|
Transform referencePoint = currentParent._referencePoint;
|
|
if (referencePoint == null) return false;
|
|
|
|
var currentPosition = referencePoint.position;
|
|
var currentRotation = currentParent.transform.rotation;
|
|
|
|
// Keep only the Y-axis rotation
|
|
currentRotation = Quaternion.Euler(0f, currentRotation.eulerAngles.y, 0f);
|
|
|
|
var deltaPosition = currentPosition - _previousPosition;
|
|
var deltaRotation = Quaternion.Inverse(_previousRotation) * currentRotation;
|
|
|
|
var platformPivot = transform.position;
|
|
avatarIKSolver.AddPlatformMotion(deltaPosition, deltaRotation, platformPivot);
|
|
|
|
_previousPosition = currentPosition;
|
|
_previousRotation = currentRotation;
|
|
|
|
ResetDesktopVRIK();
|
|
return true;
|
|
}
|
|
|
|
public void OnPreSolverUpdate()
|
|
{
|
|
if (_isEmotePlaying) return;
|
|
|
|
bool isGrounded = movementSystem._isGrounded;
|
|
|
|
// Calculate weight
|
|
float weight = avatarIKSolver.IKPositionWeight;
|
|
weight *= 1f - movementSystem.movementVector.magnitude;
|
|
weight *= isGrounded ? 1f : 0f;
|
|
|
|
// Reset avatar offset
|
|
avatarTransform.localPosition = Vector3.zero;
|
|
avatarTransform.localRotation = Quaternion.identity;
|
|
|
|
// Set plant feet
|
|
avatarIKSolver.plantFeet = Setting_PlantFeet;
|
|
|
|
// Emulate old VRChat hip movementSystem
|
|
if (Setting_BodyLeanWeight > 0)
|
|
{
|
|
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;
|
|
}
|
|
|
|
// Make root heading follow within a set limit
|
|
if (Setting_BodyHeadingLimit > 0)
|
|
{
|
|
float weightedAngleLimit = Setting_BodyHeadingLimit * weight;
|
|
float deltaAngleRoot = Mathf.DeltaAngle(transform.eulerAngles.y, _simulatedRootAngle);
|
|
float absDeltaAngleRoot = Mathf.Abs(deltaAngleRoot);
|
|
if (absDeltaAngleRoot > weightedAngleLimit)
|
|
{
|
|
deltaAngleRoot = Mathf.Sign(deltaAngleRoot) * weightedAngleLimit;
|
|
_simulatedRootAngle = Mathf.MoveTowardsAngle(_simulatedRootAngle, 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 ResetDesktopVRIK()
|
|
{
|
|
_simulatedRootAngle = 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
|
|
locomotionLayer = avatarAnimator.GetLayerIndex("IKPose");
|
|
customIKPoseLayer = 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 InitialHumanPose);
|
|
|
|
// Dumb fix for rare upload issue
|
|
requireFixTransforms = !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, Setting_FindUnmappedToes, out bool foundUnmappedToes);
|
|
|
|
// Fix animator issue or non-human mapped toes
|
|
avatarVRIK.fixTransforms = requireFixTransforms || foundUnmappedToes;
|
|
|
|
// 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.neckStiffness = 0.0001f;
|
|
avatarIKSolver.spine.bodyPosStiffness = 1f;
|
|
avatarIKSolver.spine.bodyRotStiffness = 0.2f;
|
|
|
|
// Disable locomotion
|
|
avatarIKSolver.locomotion.velocityFactor = 0f;
|
|
avatarIKSolver.locomotion.maxVelocity = 0f;
|
|
avatarIKSolver.locomotion.rootSpeed = 1000f;
|
|
|
|
// Disable chest rotation by hands
|
|
avatarIKSolver.spine.rotateChestByHands = 0f;
|
|
|
|
// Prioritize LookAtIK
|
|
avatarIKSolver.spine.headClampWeight = 0.2f;
|
|
|
|
// Disable going on tippytoes
|
|
avatarIKSolver.spine.positionWeight = 0f;
|
|
avatarIKSolver.spine.rotationWeight = 1f;
|
|
|
|
// 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 leftKneeNormal, out rightKneeNormal);
|
|
|
|
SetAvatarPose(AvatarPose.IKPose);
|
|
|
|
// Calculate initial IK scaling values with IKPose
|
|
VRIKUtils.CalculateInitialIKScaling(avatarVRIK, out initialFootDistance, out initialStepThreshold, out initialStepHeight);
|
|
|
|
// Setup HeadIKTarget
|
|
VRIKUtils.SetupHeadIKTarget(avatarVRIK);
|
|
|
|
// Initiate VRIK manually
|
|
VRIKUtils.InitiateVRIKSolver(avatarVRIK);
|
|
|
|
SetAvatarPose(AvatarPose.Initial);
|
|
}
|
|
|
|
void ConfigureVRIK()
|
|
{
|
|
VRIKUtils.ApplyScaleToVRIK
|
|
(
|
|
avatarVRIK,
|
|
initialFootDistance,
|
|
initialStepThreshold,
|
|
initialStepHeight,
|
|
1f
|
|
);
|
|
VRIKUtils.ApplyKneeBendNormals(avatarVRIK, leftKneeNormal, rightKneeNormal);
|
|
avatarVRIK.onPreSolverUpdate.AddListener(new UnityAction(DesktopVRIKSystem.Instance.OnPreSolverUpdate));
|
|
}
|
|
|
|
void SetAvatarPose(AvatarPose pose)
|
|
{
|
|
switch (pose)
|
|
{
|
|
case AvatarPose.Default:
|
|
if (HasCustomIKPose())
|
|
{
|
|
SetCustomLayersWeights(0f, 1f);
|
|
avatarAnimator.Update(0f);
|
|
}
|
|
else
|
|
{
|
|
SetMusclesToValue(0f);
|
|
}
|
|
break;
|
|
case AvatarPose.Initial:
|
|
HumanPoseHandler.SetHumanPose(ref InitialHumanPose);
|
|
break;
|
|
case AvatarPose.IKPose:
|
|
if (HasCustomIKPose())
|
|
{
|
|
SetCustomLayersWeights(1f, 0f);
|
|
avatarAnimator.Update(0f);
|
|
}
|
|
else
|
|
{
|
|
SetMusclesToPose(IKPoseMuscles);
|
|
}
|
|
break;
|
|
case AvatarPose.TPose:
|
|
SetMusclesToPose(BodySystem.TPoseMuscles);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool HasCustomIKPose()
|
|
{
|
|
return locomotionLayer != -1 && customIKPoseLayer != -1;
|
|
}
|
|
|
|
void SetCustomLayersWeights(float customIKPoseLayerWeight, float locomotionLayerWeight)
|
|
{
|
|
avatarAnimator.SetLayerWeight(customIKPoseLayer, customIKPoseLayerWeight);
|
|
avatarAnimator.SetLayerWeight(locomotionLayer, locomotionLayerWeight);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|