2022-01-18 17:18:15 +01:00

1012 lines
36 KiB
C#

using UnityEngine;
namespace Passer.Humanoid {
using Humanoid.Tracking;
public enum LegBones {
UpperLeg,
LowerLeg,
Foot,
Toes
}
/// <summary>
/// \ref HumanoidControl "Humanoid Control" options for leg related things
/// </summary>
///
/// \image html FootTargetInspector.png
///
/// Sensors
/// =======
/// See the list of
/// <a href="https://passervr.com/documentation/instantvr-extensions/">supported devices</a>
/// to get information on the hand target of each device.
///
/// Configuration
/// =============
/// Bones
/// -----
/// For Mecanim compatible avatars, the correct bones are detected automatically.
/// For other avatars, the correct bone Transforms can be assigned manually using the Bone parameters.
/// It is also possible to override the default bones from Mecanim with your own choice
/// by manual assignment of the bone. To return to the default bone,
/// it is sufficient to clear the applicable Bone parameter.
/// For the thumb and finger bones, only the first, proximal bone is needed,
/// other child bones will be detected automatically.
///
/// Limits
/// ------
/// For the arm bones, it is possible to configure the limits of movement. The maximum angle can be set when
/// Joint Limitations is enabled.
///
/// Settings
/// ========
/// * \ref FootTarget::rotationSpeedLimitation "Rotation Speed Limitation"
/// * \ref FootTarget::slidePrevention "Slide Prevention"
///
/// Events
/// ======
/// * \ref FootTarget::groundEvent "Ground Event"
///
[HelpURL("https://passervr.com/apis/HumanoidControl/Unity/class_passer_1_1_humanoid_1_1_foot_target.html")]
public class FootTarget : HumanoidTarget {
public bool isLeft;
public Side side;
public FootTarget() {
upperLeg = new TargetedUpperLegBone(this);
lowerLeg = new TargetedLowerLegBone(this);
foot = new TargetedFootBone(this);
toes = new TargetedToesBone(this);
}
public FootTarget otherFoot;
public LegMovements legMovements = new LegMovements();
#region Limitations
/// <summary>
/// Limits the maximum rotation speed of the joints.
/// </summary>
/// This can result in more natural movements with optical tracking solutions.
public bool rotationSpeedLimitation = false;
public const float maxUpperLegAngle = 120;
public const float maxLowerLegAngle = 130;
public const float maxFootAngle = 50;
public const float maxToesAngle = 30;
// for future use
public static readonly Vector3 minLeftUpperLegAngles = new Vector3(-130, -45, -50);
public static readonly Vector3 maxLeftUpperLegAngles = new Vector3(30, 40, 30);
public static readonly Vector3 minRightUpperLegAngles = new Vector3(-130, -40, -30);
public static readonly Vector3 maxRightUpperLegAngles = new Vector3(30, 45, 50);
public static readonly Vector3 minLeftLowerLegAngles = new Vector3(-15, float.NaN, float.NaN);
public static readonly Vector3 maxLeftLowerLegAngles = new Vector3(130, float.NaN, float.NaN);
public static readonly Vector3 minRightLowerLegAngles = new Vector3(-15, float.NaN, float.NaN);
public static readonly Vector3 maxRightLowerLegAngles = new Vector3(130, float.NaN, float.NaN);
public static readonly Vector3 minLeftFootAngles = new Vector3(-45, 0, -30);
public static readonly Vector3 maxLeftFootAngles = new Vector3(70, 0, 20);
public static readonly Vector3 minRightFootAngles = new Vector3(-45, 0, -20);
public static readonly Vector3 maxRightFootAngles = new Vector3(50, 0, 30);
public static readonly Vector3 minLeftToesAngles = new Vector3(-70, float.NaN, float.NaN);
public static readonly Vector3 maxLeftToesAngles = new Vector3(45, float.NaN, float.NaN);
public static readonly Vector3 minRightToesAngles = new Vector3(-70, float.NaN, float.NaN);
public static readonly Vector3 maxRightToesAngles = new Vector3(45, float.NaN, float.NaN);
#endregion
#region Sensors
public LegAnimator legAnimator = new LegAnimator();
public override Passer.Sensor animator { get { return legAnimator; } }
#if hSTEAMVR && hVIVETRACKER && (UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX)
public ViveTrackerLeg viveTracker = new ViveTrackerLeg();
#endif
#if hNEURON
public PerceptionNeuronLeg neuron = new PerceptionNeuronLeg();
#endif
#if hKINECT1
public Kinect1Leg kinect1 = new Kinect1Leg();
#endif
#if hKINECT2
public Kinect2Foot kinect2 = new Kinect2Foot();
#endif
#if hKINECT4
public Kinect4Leg kinect4 = new Kinect4Leg();
#endif
#if hORBBEC
public AstraLeg astra = new AstraLeg();
#endif
#if hOPTITRACK
public OptitrackLeg optitrack = new OptitrackLeg();
#endif
#if hANTILATENCY
public AntilatencyLeg antilatency = new AntilatencyLeg();
#endif
#if hCUSTOM
public CustomLeg custom = new CustomLeg();
#endif
private Humanoid.LegSensor[] sensors;
public override void InitSensors() {
if (sensors == null) {
sensors = new LegSensor[] {
legAnimator,
#if hOPENVR && hVIVETRACKER && (UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX)
viveTracker,
#endif
#if hKINECT1
kinect1,
#endif
#if hKINECT2
kinect2,
#endif
#if hKINECT4
kinect4,
#endif
#if hORBBEC
astra,
#endif
#if hNEURON
neuron,
#endif
#if hOPTITRACK
optitrack,
#endif
#if hANTILATENCY
antilatency,
#endif
#if hCUSTOM
custom,
#endif
};
}
}
public override void StartSensors() {
for (int i = 0; i < sensors.Length; i++)
sensors[i].Start(humanoid, transform);
}
protected override void UpdateSensors() {
for (int i = 0; i < sensors.Length; i++)
sensors[i].Update();
}
#endregion
#region SubTargets
public override TargetedBone main {
get { return foot; }
}
#region UpperLeg
public TargetedUpperLegBone upperLeg;
[System.Serializable]
public class TargetedUpperLegBone : TargetedBone {
private FootTarget footTarget;
public TargetedUpperLegBone(FootTarget footTarget) : base(footTarget.lowerLeg) {
this.footTarget = footTarget;
}
public override void Init() {
parent = footTarget.humanoid.hipsTarget.hips;
nextBone = footTarget.lowerLeg;
boneId = footTarget.isLeft ? Bone.LeftUpperLeg : Bone.RightUpperLeg;
if (footTarget.isLeft) {
bone.minAngles = minLeftUpperLegAngles;
bone.maxAngles = maxLeftUpperLegAngles;
}
else {
bone.minAngles = minRightUpperLegAngles;
bone.maxAngles = maxRightUpperLegAngles;
}
}
public override Quaternion DetermineRotation() {
Vector3 direction = footTarget.lowerLeg.bone.transform.position - bone.transform.position;
Vector3 humanoidForward = footTarget.humanoid.hipsTarget.hips.bone.targetRotation * Vector3.forward;
Quaternion rotation = Quaternion.LookRotation(direction, humanoidForward) * Quaternion.Euler(-90, 0, 0);
return rotation;
}
public override float GetTension() {
Quaternion restRotation = footTarget.humanoid.hipsTarget.hips.bone.targetRotation;
float tension = GetTension(restRotation, this);
return tension;
}
}
#endregion
#region LowerLeg
public TargetedLowerLegBone lowerLeg;
[System.Serializable]
public class TargetedLowerLegBone : TargetedBone {
private FootTarget footTarget;
public TargetedLowerLegBone(FootTarget footTarget) : base(footTarget.foot) {
this.footTarget = footTarget;
}
public override void Init() {
parent = footTarget.upperLeg;
nextBone = footTarget.foot;
boneId = footTarget.isLeft ? Bone.LeftLowerLeg : Bone.RightLowerLeg;
if (footTarget.isLeft) {
bone.minAngles = minLeftLowerLegAngles;
bone.maxAngles = maxLeftLowerLegAngles;
}
else {
bone.minAngles = minRightLowerLegAngles;
bone.maxAngles = maxRightLowerLegAngles;
}
}
public override Quaternion DetermineRotation() {
Vector3 direction = footTarget.foot.bone.transform.position - bone.transform.position;
Vector3 humanoidForward = footTarget.humanoid.hipsTarget.hips.bone.targetRotation * Vector3.forward;
Quaternion rotation = Quaternion.LookRotation(direction, humanoidForward) * Quaternion.Euler(-90, 0, 0);
return rotation;
}
public override float GetTension() {
Quaternion restRotation = footTarget.upperLeg.bone.targetRotation;
float tension = GetTension(restRotation, this);
return tension;
}
}
#endregion
#region Foot
public TargetedFootBone foot;
[System.Serializable]
public class TargetedFootBone : TargetedBone {
private FootTarget footTarget;
public TargetedFootBone(FootTarget footTarget) : base(footTarget.toes) {
this.footTarget = footTarget;
}
public override void Init() {
parent = footTarget.lowerLeg;
nextBone = footTarget.toes;
boneId = footTarget.isLeft ? Bone.LeftFoot : Bone.RightFoot;
if (footTarget.isLeft) {
bone.minAngles = minLeftFootAngles;
bone.maxAngles = maxLeftFootAngles;
}
else {
bone.minAngles = minRightFootAngles;
bone.maxAngles = maxRightFootAngles;
}
}
public override Quaternion DetermineRotation() {
if (footTarget.humanoid.transform == null)
return Quaternion.identity;
Vector3 humanoidUp = footTarget.humanoid.up;
if (footTarget.toes.bone.transform != null) {
Vector3 direction = footTarget.toes.bone.transform.position - bone.transform.position;
Quaternion rotation = Quaternion.LookRotation(direction, humanoidUp);
bone.baseRotation = Quaternion.Inverse(footTarget.humanoid.transform.rotation) * rotation;
}
float humanoidRotation = footTarget.humanoid.hipsTarget.hips.bone.targetRotation.eulerAngles.y;
Quaternion footRotation = Quaternion.AngleAxis(humanoidRotation, humanoidUp);
return footRotation;
}
public override float GetTension() {
Quaternion restRotation = footTarget.lowerLeg.bone.targetRotation; // * Quaternion.AngleAxis(90, Vector3.right);
float tension = GetTension(restRotation, this);
return tension;
}
protected override void DetermineBasePosition() {
if (target.basePosition.sqrMagnitude != 0)
// Base Position is already determined
return;
Transform basePositionReference = GetBasePositionReference();
target.basePosition = basePositionReference.InverseTransformPoint(target.transform.position);
}
public override Vector3 TargetBasePosition() {
Transform basePositionReference = GetBasePositionReference();
Vector3 basePosition = basePositionReference.TransformPoint(target.basePosition);
return basePosition;
}
private Transform GetBasePositionReference() {
return footTarget.humanoid.transform;
}
}
#endregion
#region Toes
public TargetedToesBone toes;
[System.Serializable]
public class TargetedToesBone : TargetedBone {
private FootTarget footTarget;
public TargetedToesBone(FootTarget footTarget) {
this.footTarget = footTarget;
}
public override void Init() {
parent = footTarget.foot;
nextBone = null;
boneId = footTarget.isLeft ? Bone.LeftToes : Bone.RightToes;
if (footTarget.isLeft) {
bone.minAngles = minLeftToesAngles;
bone.maxAngles = maxLeftToesAngles;
}
else {
bone.minAngles = minRightToesAngles;
bone.maxAngles = maxRightToesAngles;
}
}
public override float GetTension() {
Quaternion restRotation = footTarget.foot.bone.targetRotation;
float tension = GetTension(restRotation, this);
return tension;
}
public override Quaternion DetermineRotation() {
if (footTarget.humanoid.transform != null) {
float humanoidRotation = footTarget.humanoid.hipsTarget.hips.bone.targetRotation.eulerAngles.y;
Quaternion toesRotation = Quaternion.AngleAxis(humanoidRotation, footTarget.humanoid.up);
return toesRotation;
}
else
return Quaternion.identity;
}
}
#endregion
protected void InitSubTargets() {
upperLeg.Init();
lowerLeg.Init();
foot.Init();
toes.Init();
}
private void SetTargetPositionsToAvatar() {
upperLeg.SetTargetPositionToAvatar();
lowerLeg.SetTargetPositionToAvatar();
foot.SetTargetPositionToAvatar();
toes.SetTargetPositionToAvatar();
}
private void DoMeasurements() {
upperLeg.DoMeasurements();
lowerLeg.DoMeasurements();
foot.DoMeasurements();
toes.DoMeasurements();
}
public Bone GetBoneId(bool isLeft, LegBones armBone) {
if (isLeft) {
switch (armBone) {
case LegBones.UpperLeg:
return Bone.LeftUpperLeg;
case LegBones.LowerLeg:
return Bone.LeftLowerLeg;
case LegBones.Foot:
return Bone.LeftFoot;
case LegBones.Toes:
return Bone.LeftToes;
}
}
else {
switch (armBone) {
case LegBones.UpperLeg:
return Bone.RightUpperLeg;
case LegBones.LowerLeg:
return Bone.RightLowerLeg;
case LegBones.Foot:
return Bone.RightFoot;
case LegBones.Toes:
return Bone.RightToes;
}
}
return Bone.None;
}
public TargetedBone GetTargetBone(LegBones boneID) {
switch (boneID) {
case LegBones.UpperLeg:
return upperLeg;
case LegBones.LowerLeg:
return lowerLeg;
case LegBones.Foot:
return foot;
case LegBones.Toes:
return toes;
default:
return null;
}
}
#endregion
#region Configuration
public virtual void ClearBones() {
upperLeg.bone.transform = null;
lowerLeg.bone.transform = null;
foot.bone.transform = null;
toes.bone.transform = null;
}
public override Transform GetDefaultTarget(HumanoidControl humanoid) {
Transform targetTransform = null;
GetDefaultBone(humanoid.targetsRig, ref targetTransform, isLeft ? HumanBodyBones.LeftFoot : HumanBodyBones.RightFoot);
return targetTransform;
}
// Do not remove this, this is dynamically called from Target_Editor!
public static FootTarget CreateTarget(FootTarget oldTarget) {
HumanoidControl humanoid = oldTarget.humanoid;
GameObject targetObject = new GameObject();
if (oldTarget.isLeft)
targetObject.name = "Left Foot Target";
else
targetObject.name = "Right Foot Target";
Transform targetTransform = targetObject.transform;
targetTransform.parent = humanoid.transform;
targetTransform.position = oldTarget.transform.position;
targetTransform.rotation = oldTarget.transform.rotation;
FootTarget footTarget = Constructor(humanoid, oldTarget.isLeft, targetTransform);
if (footTarget.isLeft)
humanoid.leftFootTarget = footTarget;
else
humanoid.rightFootTarget = footTarget;
footTarget.RetrieveBones();
footTarget.InitAvatar();
footTarget.MatchTargetsToAvatar();
return footTarget;
}
// Do not remove this, this is dynamically called from Target_Editor!
// Changes the target transform used for this head target
// Generates a new headtarget component, so parameters will be lost if transform is changed
public static FootTarget SetTarget(HumanoidControl humanoid, Transform targetTransform, bool isLeft) {
FootTarget currentFootTarget = isLeft ? humanoid.leftFootTarget : humanoid.rightFootTarget;
if (targetTransform == currentFootTarget.transform)
return currentFootTarget;
GetDefaultBone(humanoid.targetsRig, ref targetTransform, isLeft ? HumanBodyBones.LeftFoot : HumanBodyBones.RightFoot);
if (targetTransform == null)
return currentFootTarget;
FootTarget footTarget = targetTransform.GetComponent<FootTarget>();
if (footTarget == null)
footTarget = targetTransform.gameObject.AddComponent<FootTarget>();
if (isLeft)
humanoid.leftFootTarget = footTarget;
else
humanoid.rightFootTarget = footTarget;
footTarget.NewComponent(humanoid);
return footTarget;
}
public void RetrieveBones() {
upperLeg.RetrieveBones(humanoid);
lowerLeg.RetrieveBones(humanoid);
foot.RetrieveBones(humanoid);
toes.RetrieveBones(humanoid);
}
#endregion
#region Settings
public bool jointLimitations = true;
/// <summary>
/// Prevents movement of the foot when it is on the ground.
/// </summary>
public bool slidePrevention = false;
public bool physics = true;
public void ShowControllers(bool shown) {
if (sensors == null)
return;
for (int i = 0; i < sensors.Length - 1; i++)
sensors[i].ShowSensor(this, shown);
}
#endregion
#region Events
/// <summary>
/// Use to call functions based on the foot touching the ground.
/// </summary>
public GameObjectEventHandlers groundEvent = new GameObjectEventHandlers() {
id = 1,
label = "Ground Event",
tooltip =
"Call function based on ground standing\n" +
"Parameter: the ground object",
eventTypeLabels = new string[] {
"Never",
"On Grounded",
"On not Grounded",
"While Grounded",
"While not Grounded",
"When Ground Changes",
"Always"
},
fromEventLabel = "ground.gameObject"
};
protected virtual void UpdateEvents() {
if (ground == null)
groundEvent.value = null;
else
groundEvent.value = ground.gameObject;
}
#endregion
#region Ground
public Transform ground;
// the ground on which the foot is standing, == null when the foot is not on the ground
public Vector3 groundNormal = Vector3.up;
// the normal of the ground on which the foot in standing
public Vector3 groundTranslation = Vector3.zero;
// the amount the ground moved since last update
public float groundDistance = 0;
// the distance to the ground
#region private
[HideInInspector]
private Transform lastGround;
[HideInInspector]
private Vector3 lastGroundPosition = Vector3.zero;
private void CheckGroundMovement() {
if (ground != null && ground == lastGround && lastGroundPosition.sqrMagnitude != 0) {
groundTranslation = ground.position - lastGroundPosition;
}
else {
groundTranslation = Vector3.zero;
}
lastGround = ground;
if (ground != null)
lastGroundPosition = ground.position;
else
lastGroundPosition = Vector3.zero;
}
#endregion
#endregion
public float soleThicknessFoot;
public float soleThicknessToes;
#region Init
public static bool IsInitialized(HumanoidControl humanoid) {
if (humanoid.leftFootTarget == null || humanoid.leftFootTarget.humanoid == null)
return false;
if (humanoid.rightFootTarget == null || humanoid.rightFootTarget.humanoid == null)
return false;
if (humanoid.leftFootTarget.foot.target.transform == null || humanoid.leftFootTarget.foot.target.transform == null)
return false;
if (humanoid.leftFootTarget.foot.bone.transform == null && humanoid.rightFootTarget.foot.bone.transform == null)
return false;
return true;
}
private void Reset() {
humanoid = GetHumanoid();
if (humanoid == null)
return;
NewComponent(humanoid);
upperLeg.bone.maxAngle = maxUpperLegAngle;
lowerLeg.bone.maxAngle = maxLowerLegAngle;
foot.bone.maxAngle = maxFootAngle;
toes.bone.maxAngle = maxToesAngle;
}
private HumanoidControl GetHumanoid() {
// This does not work for prefabs
HumanoidControl[] humanoids = FindObjectsOfType<HumanoidControl>();
for (int i = 0; i < humanoids.Length; i++) {
if ((humanoids[i].leftFootTarget != null && humanoids[i].leftFootTarget.transform == this.transform) ||
(humanoids[i].rightFootTarget != null && humanoids[i].rightFootTarget.transform == this.transform)) {
return humanoids[i];
}
}
return null;
}
public override void InitAvatar() {
InitSubTargets();
otherFoot = isLeft ? humanoid.rightFootTarget : humanoid.leftFootTarget;
upperLeg.DoMeasurements();
lowerLeg.DoMeasurements();
foot.DoMeasurements();
toes.DoMeasurements();
#if pCEREBELLUM
Cerebellum_InitAvatar();
#endif
}
#if pCEREBELLUM
private void Cerebellum_InitAvatar() {
Bone boneId;
ICerebellumJoint cJoint;
boneId = GetBoneId(isLeft, LegBones.UpperLeg);
cJoint = humanoid.cerebellum.GetJoint(boneId);
cJoint.position = upperLeg.bone.transform.position;
cJoint.orientation = upperLeg.bone.transform.rotation;
boneId = GetBoneId(isLeft, LegBones.LowerLeg);
cJoint = humanoid.cerebellum.GetJoint(boneId);
cJoint.position = lowerLeg.bone.transform.position;
cJoint.orientation = lowerLeg.bone.transform.rotation;
boneId = GetBoneId(isLeft, LegBones.Foot);
cJoint = humanoid.cerebellum.GetJoint(boneId);
cJoint.position = foot.bone.transform.position;
cJoint.orientation = foot.bone.transform.rotation;
boneId = GetBoneId(isLeft, LegBones.Toes);
cJoint = humanoid.cerebellum.GetJoint(boneId);
cJoint.position = toes.bone.transform.position;
cJoint.orientation = toes.bone.transform.rotation;
}
#endif
private static FootTarget Constructor(HumanoidControl humanoid, bool isLeft, Transform targetTransform) {
FootTarget footTarget = targetTransform.gameObject.AddComponent<FootTarget>();
footTarget.humanoid = humanoid;
footTarget.isLeft = isLeft;
footTarget.side = isLeft ? Side.Left : Side.Right;
footTarget.otherFoot = isLeft ? humanoid.rightFootTarget : humanoid.leftFootTarget;
footTarget.InitSubTargets();
return footTarget;
}
public override void NewComponent(HumanoidControl _humanoid) {
humanoid = _humanoid;
isLeft = (this == humanoid.leftFootTarget);
otherFoot = isLeft ? humanoid.rightFootTarget : humanoid.leftFootTarget;
InitComponent();
}
public override void InitComponent() {
if (humanoid == null)
return;
InitSubTargets();
RetrieveBones();
// We need to do this before the measurements
SetTargetPositionsToAvatar();
DoMeasurements();
}
public override void StartTarget() {
side = isLeft ? Side.Left : Side.Right;
InitSensors();
if (foot.bone.transform != null)
soleThicknessFoot = foot.bone.transform.position.y - humanoid.transform.position.y;
else
soleThicknessFoot = foot.target.transform.position.y - humanoid.transform.position.y;
if (toes.bone.transform != null && ground != null)
soleThicknessToes = toes.bone.transform.position.y - humanoid.transform.position.y;
else
soleThicknessToes = soleThicknessFoot;
legMovements.Start(humanoid, this);
}
public bool IsInTPose() {
if (foot.bone.transform != null) {
float d;
Ray upper2foot = new Ray(upperLeg.bone.transform.position, foot.bone.transform.position - upperLeg.bone.transform.position);
// Vertical? (needs adjustments for mini avatars)
if (Mathf.Abs(upper2foot.direction.x) > 0.1F ||
Mathf.Abs(upper2foot.direction.z) > 0.1F)
return false;
// All lined up?
d = Vectors.DistanceToRay(upper2foot, lowerLeg.bone.transform.position);
if (d > 0.05F)
return false;
// Leg stretched?
d = Vector3.Distance(upperLeg.bone.transform.position, foot.bone.transform.position);
if (d < upperLeg.bone.length - 0.05F)
return false;
return true;
}
else
return false;
}
/// <summary>
/// Checks whether the humanoid has a FootTarget
/// and adds one if none has been found
/// </summary>
/// <param name="humanoid">The humanoid to check</param>
/// <param name="isLeft">Is this the left foot?</param>
public static void DetermineTarget(HumanoidControl humanoid, bool isLeft) {
FootTarget footTarget = isLeft ? humanoid.leftFootTarget : humanoid.rightFootTarget;
if (footTarget == null) {
Transform footTargetTransform = humanoid.targetsRig.GetBoneTransform(isLeft ? HumanBodyBones.LeftFoot : HumanBodyBones.RightFoot);
if (footTargetTransform == null) {
Debug.LogError("Could not find foot bone in targets rig");
return;
}
footTarget = footTargetTransform.GetComponent<FootTarget>();
if (footTarget == null) {
footTarget = Constructor(humanoid, isLeft, footTargetTransform);
}
}
if (isLeft)
humanoid.leftFootTarget = footTarget;
else
humanoid.rightFootTarget = footTarget;
}
public override void MatchTargetsToAvatar() {
upperLeg.MatchTargetToAvatar();
lowerLeg.MatchTargetToAvatar();
foot.MatchTargetToAvatar();
if (main.target.transform && transform != null) {
if (!Application.isPlaying) {
float targetDistance = Vector3.Distance(transform.position, main.target.transform.position);
if (targetDistance > 0.001F)
transform.position = main.target.transform.position;
}
else
transform.position = main.target.transform.position;
transform.rotation = main.target.transform.rotation;
}
toes.MatchTargetToAvatar();
}
#endregion
#region Update
public override void UpdateTarget() {
upperLeg.target.confidence = Confidence.none;
lowerLeg.target.confidence = Confidence.none;
foot.target.confidence = Confidence.none;
UpdateSensors();
CheckGroundMovement();
if (slidePrevention)
SlidePrevention();
foot.CalculateVelocity();
#if pCEREBELLUM
SetTargets();
#endif
UpdateEvents();
}
#if pCEREBELLUM
private void SetTargets() {
SetTargetTransform(LegBones.UpperLeg, upperLeg.target);
SetTargetTransform(LegBones.LowerLeg, lowerLeg.target);
SetTargetTransform(LegBones.Foot, foot.target);
SetTargetTransform(LegBones.Toes, toes.target);
}
private void SetTargetTransform(LegBones legBone, TargetTransform target) {
if (humanoid.cerebellum == null || target.transform == null)
return;
Bone boneId = GetBoneId(isLeft, legBone);
ICerebellumTarget cTarget = humanoid.cerebellum.GetTarget(boneId);
cTarget.SetPosition(target.transform.position, target.confidence.position);
cTarget.SetOrientation(target.transform.rotation, target.confidence.rotation);
}
#endif
public override void UpdateMovements(HumanoidControl humanoid) {
if (humanoid == null || !humanoid.calculateBodyPose)
return;
LegMovements.Update(this);
#if pCEREBELLUM
if (isLeft) {
if (humanoid.cerebellum != null) {
ICerebellumJoint cJoint;
cJoint = humanoid.cerebellum.GetJoint(Bone.LeftUpperLeg);
upperLeg.bone.transform.rotation = cJoint.orientation;
cJoint = humanoid.cerebellum.GetJoint(Bone.LeftLowerLeg);
lowerLeg.bone.transform.rotation = cJoint.orientation;
cJoint = humanoid.cerebellum.GetJoint(Bone.LeftFoot);
foot.bone.transform.rotation = cJoint.orientation;
}
}
#endif
}
public override void CopyTargetToRig() {
if (Application.isPlaying &&
humanoid.animatorEnabled && humanoid.targetsRig.runtimeAnimatorController != null)
return;
if (foot.target.transform == null || transform == foot.target.transform)
return;
if (foot.target.transform != null && transform != foot.target.transform) {
foot.target.transform.position = transform.position;
foot.target.transform.rotation = transform.rotation;
}
#if pCEREBELLUM
SetTargets();
#endif
}
public override void CopyRigToTarget() {
if (foot.target.transform == null || transform == foot.target.transform)
return;
if (!Application.isPlaying && foot.bone.transform != null) {
float targetDistance = Vector3.Distance(foot.bone.transform.position, foot.target.transform.position);
if (targetDistance < 0.001F)
return;
}
transform.position = foot.target.transform.position;
transform.rotation = foot.target.transform.rotation;
}
public void UpdateSensorsFromTarget() {
if (sensors == null)
return;
for (int i = 0; i < sensors.Length; i++)
sensors[i].UpdateSensorTransformFromTarget(this.transform);
}
#endregion
#region Ground
public void CheckGrounded() {
if (foot.target.transform == null)
return;
Vector3 checkStartPosition = foot.target.transform.position - (soleThicknessFoot - humanoid.stepOffset) * humanoid.up;
groundDistance = humanoid.GetDistanceToGroundAt(checkStartPosition, humanoid.stepOffset * 1.2F, out ground, out groundNormal);
groundDistance += humanoid.stepOffset;
if (groundDistance < -0.02F)
ground = null;
//else
//groundDistance = 0;
}
#endregion
#region SlidePrevention
Vector3 lastPosition;
private void SlidePrevention() {
Vector3 localPosition = foot.target.transform.position - humanoid.transform.position;
if (ground == null) {
// Foot is not on the ground
lastPosition = localPosition;
return;
}
bool isStandingLeg = true;
if (otherFoot.ground != null && otherFoot.foot.target.transform.position.y < foot.target.transform.position.y)
// Other foot is also on the ground, but it is lower, so that foot should not slide
isStandingLeg = false;
Vector3 delta = new Vector3(localPosition.x - lastPosition.x, 0, localPosition.z - lastPosition.z);
float slideDistance = delta.magnitude;
if (slideDistance > 0.001F && slideDistance < 0.15F) {
if (foot.target.confidence.position > 0 &&
foot.target.confidence.position >= humanoid.hipsTarget.hips.target.confidence.position &&
foot.target.confidence.position >= humanoid.headTarget.head.target.confidence.position &&
isStandingLeg) {
// We are sliding on the ground with this leg, move the humanoid in opposite direction
humanoid.transform.position -= delta;
}
else {
// Move the foot in the opposite direction
foot.target.transform.position -= delta;
}
}
lastPosition = localPosition;
}
#endregion
#region DrawRigs
protected override void DrawTargetRig(HumanoidControl humanoid) {
if (this != humanoid.leftFootTarget && this != humanoid.rightFootTarget)
return;
DrawTarget(upperLeg.target.confidence, upperLeg.target.transform, Vector3.down, upperLeg.target.length);
DrawTarget(lowerLeg.target.confidence, lowerLeg.target.transform, Vector3.down, lowerLeg.target.length);
DrawTarget(foot.target.confidence, foot.target.transform, Vector3.forward, foot.target.length);
}
protected override void DrawAvatarRig(HumanoidControl humanoid) {
if (this != humanoid.leftFootTarget && this != humanoid.rightFootTarget)
return;
if (upperLeg.bone.transform != null)
DrawAvatarBone(upperLeg, Vector3.down);
if (lowerLeg.bone.transform != null)
DrawAvatarBone(lowerLeg, Vector3.down);
if (foot.bone.transform != null)
DrawAvatarBone(foot, Vector3.forward);
}
#endregion
}
}