Update
This commit is contained in:
@@ -0,0 +1,288 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Invector.IK
|
||||
{
|
||||
using Invector;
|
||||
/// <summary>
|
||||
/// Class that helps to Align arm to a position using a <seealso cref="aimReference"/>
|
||||
/// </summary>
|
||||
public class vArmAimAlign
|
||||
{
|
||||
#region Bones
|
||||
protected Transform root;
|
||||
protected Transform upperArm;
|
||||
protected Transform foreArm;
|
||||
protected Transform hand;
|
||||
|
||||
public bool smoothIKAlignmentPoint = true;
|
||||
#endregion
|
||||
|
||||
#region Bone Helpers
|
||||
public Transform upperArmHelper { get; protected set; }
|
||||
public Transform foreArmHelper { get; protected set; }
|
||||
public Transform handHelper { get; protected set; }
|
||||
public Transform aimReferenceHelper { get; protected set; }
|
||||
#endregion
|
||||
|
||||
#region public Variables
|
||||
/// <summary>
|
||||
/// Smooth the alignment
|
||||
/// </summary>
|
||||
public float smooth { get; set; }
|
||||
/// <summary>
|
||||
/// Max angle (x) of the alignment based on Aim Reference
|
||||
/// </summary>
|
||||
public float maxVerticalAligmentAngle { get; set; }
|
||||
/// <summary>
|
||||
/// Max angle (y) of the alignment based on Aim Reference
|
||||
/// </summary>
|
||||
public float maxHorizontalAligmentAngle { get; set; }
|
||||
/// <summary>
|
||||
/// Reference transform to align arm. if this transform be null, the arm don't will be aligned;
|
||||
/// </summary>
|
||||
public Transform aimReference { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Protected Variables
|
||||
protected Quaternion _upperArmRotation;
|
||||
protected Quaternion _foreArmRotation;
|
||||
protected Quaternion _handRotation;
|
||||
protected Quaternion _aimReferenceRotation;
|
||||
protected Quaternion _upperArmRotationSmooth;
|
||||
protected Quaternion _handRotationSmooth;
|
||||
protected Quaternion smoothRotationDirection;
|
||||
|
||||
protected Vector3 _upperArmPosition;
|
||||
protected Vector3 _foreArmPosition;
|
||||
protected Vector3 _handPosition;
|
||||
protected Vector3 _aimReferencePosition;
|
||||
#endregion
|
||||
|
||||
public vArmAimAlign(Transform upperArm, Transform foreArm, Transform hand)
|
||||
{
|
||||
this.upperArm = upperArm;
|
||||
this.foreArm = foreArm;
|
||||
this.hand = hand;
|
||||
|
||||
if (!upperArm || !foreArm || !hand) return;
|
||||
|
||||
root = upperArm.parent;
|
||||
if (!upperArmHelper)
|
||||
{
|
||||
upperArmHelper = new GameObject("UpperArmHelper").transform;
|
||||
upperArmHelper.gameObject.tag = "Ignore Ragdoll";
|
||||
}
|
||||
if (!foreArmHelper)
|
||||
{
|
||||
foreArmHelper = new GameObject("ForeArmHelper").transform;
|
||||
foreArmHelper.gameObject.tag = "Ignore Ragdoll";
|
||||
}
|
||||
if (!handHelper)
|
||||
{
|
||||
handHelper = new GameObject("HandHelper").transform;
|
||||
handHelper.gameObject.tag = "Ignore Ragdoll";
|
||||
}
|
||||
if (!aimReferenceHelper)
|
||||
{
|
||||
aimReferenceHelper = new GameObject("AimReferenceHelper").transform;
|
||||
aimReferenceHelper.gameObject.tag = "Ignore Ragdoll";
|
||||
}
|
||||
|
||||
upperArmHelper.parent = root;
|
||||
foreArmHelper.parent = upperArmHelper;
|
||||
handHelper.parent = foreArmHelper;
|
||||
aimReferenceHelper.parent = handHelper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if the Arm is valid (all necessary transforms is assigned)
|
||||
/// </summary>
|
||||
public bool IsValid => this.upperArm && this.foreArm && this.hand && this.aimReference;
|
||||
|
||||
/// <summary>
|
||||
/// Update Arm to use default animation alignment
|
||||
/// </summary>
|
||||
/// <param name="aimReference"></param>
|
||||
public void UpdateDefaultAlignment()
|
||||
{
|
||||
if (!IsValid) return;
|
||||
upperArmHelper.SetPositionAndRotation(upperArm.position, upperArm.rotation);
|
||||
upperArmHelper.localScale = upperArm.localScale;
|
||||
foreArmHelper.SetPositionAndRotation(foreArm.position, foreArm.rotation);
|
||||
foreArmHelper.localScale = foreArm.localScale;
|
||||
handHelper.SetPositionAndRotation(hand.position, hand.rotation);
|
||||
handHelper.localScale = hand.localScale;
|
||||
aimReferenceHelper.SetPositionAndRotation(aimReference.position, aimReference.rotation);
|
||||
aimReferenceHelper.localScale = aimReference.localScale;
|
||||
|
||||
_upperArmRotation = upperArmHelper.localRotation;
|
||||
_foreArmRotation = foreArmHelper.localRotation;
|
||||
_handRotation = handHelper.localRotation;
|
||||
_aimReferenceRotation = aimReferenceHelper.localRotation;
|
||||
|
||||
_upperArmPosition = upperArmHelper.localPosition;
|
||||
_foreArmPosition = foreArmHelper.localPosition;
|
||||
_handPosition = handHelper.localPosition;
|
||||
_aimReferencePosition = aimReferenceHelper.localPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restore last alignment applied from <seealso cref="AlignToArmToPosition"/>
|
||||
/// </summary>
|
||||
/// <param name="aimReference"></param>
|
||||
public void RestoreToLastAlignment()
|
||||
{
|
||||
if (!IsValid) return;
|
||||
upperArmHelper.localRotation = _upperArmRotation;
|
||||
foreArmHelper.localRotation = _foreArmRotation;
|
||||
handHelper.localRotation = _handRotation;
|
||||
aimReferenceHelper.localRotation = _aimReferenceRotation;
|
||||
|
||||
upperArmHelper.localPosition = _upperArmPosition;
|
||||
foreArmHelper.localPosition = _foreArmPosition;
|
||||
handHelper.localPosition = _handPosition;
|
||||
aimReferenceHelper.localPosition = _aimReferencePosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Align Arm to a position
|
||||
/// </summary>
|
||||
/// <param name="targetPosition">position to align Arm</param>
|
||||
/// <param name="weight">alignment weight (0~1)</param>
|
||||
/// <param name="alignUpperArm"></param>
|
||||
/// <param name="alignHand"></param>
|
||||
public void AlignToArmToPosition(Vector3 targetPosition, float weight, bool alignUpperArm = true, bool alignHand = true)
|
||||
{
|
||||
if (!IsValid) return;
|
||||
|
||||
if (smoothIKAlignmentPoint)
|
||||
{
|
||||
targetPosition = SmootAndClampPosition(targetPosition, maxHorizontalAligmentAngle, maxVerticalAligmentAngle);
|
||||
}
|
||||
|
||||
if (alignUpperArm) AlignUpperArm(targetPosition, alignHand ? weight * 0.5f : weight);
|
||||
if (alignHand) AlignHand(targetPosition, weight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Align upper arm to a position
|
||||
/// </summary>
|
||||
/// <param name="targetPosition">position to align upper arm</param>
|
||||
/// <param name="weight">alignment weight (0~1)</param>
|
||||
protected virtual void AlignUpperArm(Vector3 targetPosition, float weight)
|
||||
{
|
||||
AlignArmBone(upperArm, upperArmHelper, ref _upperArmRotationSmooth, targetPosition, weight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Align hand to a position
|
||||
/// </summary>
|
||||
/// <param name="targetPosition">position to align hand</param>
|
||||
/// <param name="weight">alignment weight (0~1)</param>
|
||||
protected virtual void AlignHand(Vector3 targetPosition, float weight)
|
||||
{
|
||||
AlignArmBone(hand, handHelper, ref _handRotationSmooth, targetPosition, weight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Align bone to a target position
|
||||
/// </summary>
|
||||
/// <param name="bone">target bone</param>
|
||||
/// <param name="boneHelper">target bone helper</param>
|
||||
/// <param name="smoothRotation">rotation of this bone (used to smooth)</param>
|
||||
/// <param name="targetPosition">position to align bone </param>
|
||||
/// <param name="weight">alignment weight (0~1)</param>
|
||||
protected virtual void AlignArmBone(Transform bone, Transform boneHelper, ref Quaternion smoothRotation, Vector3 targetPosition, float weight)
|
||||
{
|
||||
if (!smoothIKAlignmentPoint && System.Math.Round(weight, 1) == 0)
|
||||
{
|
||||
smoothRotation = Quaternion.identity;
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 v = targetPosition - aimReferenceHelper.position;
|
||||
|
||||
Quaternion targetRotation = Quaternion.identity;
|
||||
|
||||
if (!smoothIKAlignmentPoint)
|
||||
{
|
||||
targetRotation = ClampRotation(Quaternion.LookRotation(v, aimReferenceHelper.up), maxHorizontalAligmentAngle * (weight), maxVerticalAligmentAngle * (weight));
|
||||
}
|
||||
else
|
||||
{
|
||||
targetRotation = Quaternion.LookRotation(v, aimReferenceHelper.up);
|
||||
}
|
||||
var currentOrientation = boneHelper.InverseTransformDirection(aimReferenceHelper.forward);
|
||||
var targetOrientation = boneHelper.InverseTransformDirection(targetRotation * Vector3.forward);
|
||||
|
||||
var alignmentRotation = Quaternion.FromToRotation(currentOrientation, targetOrientation);
|
||||
|
||||
if ((!float.IsNaN(alignmentRotation.x) && !float.IsNaN(alignmentRotation.y) && !float.IsNaN(alignmentRotation.z)))
|
||||
{
|
||||
Quaternion additiveRotation;
|
||||
if (!smoothIKAlignmentPoint)
|
||||
{
|
||||
smoothRotation = Quaternion.Slerp(smoothRotation, Quaternion.Lerp(Quaternion.identity, alignmentRotation, weight), smooth * Time.fixedDeltaTime);
|
||||
additiveRotation = smoothRotation;
|
||||
}
|
||||
else
|
||||
additiveRotation = Quaternion.Lerp(Quaternion.identity, alignmentRotation, weight);
|
||||
|
||||
bone.localRotation *= additiveRotation;
|
||||
boneHelper.localRotation *= additiveRotation;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamp the target IK alignment rotation base to <see cref="aimReferenceHelper"/> transform
|
||||
/// </summary>
|
||||
/// <param name="rotation">rotation to clamp</param>
|
||||
/// <param name="maxHorizontalAngle">max horizontal angle (y)</param>
|
||||
/// <param name="maxVerticalAngle">max vertical angle (x)</param>
|
||||
/// <returns></returns>
|
||||
protected virtual Quaternion ClampRotation(Quaternion rotation, float maxHorizontalAngle, float maxVerticalAngle)
|
||||
{
|
||||
var direction = rotation * Vector3.forward;
|
||||
var localDirection = aimReferenceHelper.InverseTransformDirection(direction);
|
||||
var localRotation = Quaternion.LookRotation(localDirection);
|
||||
var rotationEuler = localRotation.eulerAngles.NormalizeAngle();
|
||||
rotationEuler.y = Mathf.Clamp(rotationEuler.y, -maxHorizontalAngle, maxHorizontalAngle);
|
||||
rotationEuler.x = Mathf.Clamp(rotationEuler.x, -maxVerticalAngle, maxVerticalAngle);
|
||||
rotationEuler.z = 0;
|
||||
direction = aimReferenceHelper.TransformDirection(Quaternion.Euler(rotationEuler.NormalizeAngle()) * Vector3.forward);
|
||||
return Quaternion.LookRotation(direction, aimReferenceHelper.up);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply smooth and Clamp to the target Ik alignment Position base to <see cref="aimReferenceHelper"/> transform
|
||||
/// </summary>
|
||||
/// <param name="position">position to clamp smoothly</param>
|
||||
/// <param name="maxHorizontalAngle"></param>
|
||||
/// <param name="maxVerticalAngle"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual Vector3 SmootAndClampPosition(Vector3 position, float maxHorizontalAngle, float maxVerticalAngle)
|
||||
{
|
||||
var direction = position - aimReferenceHelper.position;
|
||||
smoothRotationDirection = Quaternion.Slerp(ClampRotation(smoothRotationDirection, maxHorizontalAngle, maxVerticalAngle), Quaternion.LookRotation(position - aimReferenceHelper.position, aimReferenceHelper.up), smooth * Time.fixedDeltaTime);
|
||||
position = aimReferenceHelper.position + smoothRotationDirection * Vector3.forward * direction.magnitude;
|
||||
return position;
|
||||
}
|
||||
|
||||
public void DrawBones(Color color)
|
||||
{
|
||||
if (!IsValid) return;
|
||||
Debug.DrawLine(upperArm.position, foreArm.position, color);
|
||||
Debug.DrawLine(foreArm.position, hand.position, color);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void DrawHelpers(Color color)
|
||||
{
|
||||
if (!IsValid) return;
|
||||
Debug.DrawLine(upperArmHelper.position, foreArmHelper.position, color);
|
||||
Debug.DrawLine(foreArmHelper.position, handHelper.position, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9970c6836d653842ab68a548ac79a75
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,268 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Invector.IK
|
||||
{
|
||||
[System.Serializable]
|
||||
public class vIKSolver
|
||||
{
|
||||
public Transform rootTransform;
|
||||
public Transform rootBone;
|
||||
public Transform middleBone;
|
||||
public Transform endBone;
|
||||
[Header("Optional")]
|
||||
public Transform endBoneRef;
|
||||
public Transform middleBoneRef;
|
||||
public Transform endBoneOffset;
|
||||
public Transform middleBoneOffset;
|
||||
|
||||
string middleTag, endTag;
|
||||
float _weight;
|
||||
Vector3? hintPosition;
|
||||
/// <summary>
|
||||
/// Manual creation of the bone targets
|
||||
/// </summary>
|
||||
/// <param name="rootBone"></param>
|
||||
/// <param name="middleBone"></param>
|
||||
/// <param name="endBone"></param>
|
||||
public vIKSolver(Transform rootTransform, Transform rootBone, Transform middleBone, Transform endBone)
|
||||
{
|
||||
this.rootTransform = rootTransform;
|
||||
this.rootBone = rootBone;
|
||||
this.middleBone = middleBone;
|
||||
this.endBone = endBone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Auto creation of the bone targets
|
||||
/// </summary>
|
||||
/// <param name="animator"></param>
|
||||
/// <param name="ikGoal"></param>
|
||||
public vIKSolver(Animator animator, AvatarIKGoal ikGoal)
|
||||
{
|
||||
if (animator == null) { return; }
|
||||
this.rootTransform = animator.transform;
|
||||
if (animator.isHuman)
|
||||
{
|
||||
switch (ikGoal)
|
||||
{
|
||||
case AvatarIKGoal.LeftHand:
|
||||
rootBone = animator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
|
||||
middleBone = animator.GetBoneTransform(HumanBodyBones.LeftLowerArm);
|
||||
endBone = animator.GetBoneTransform(HumanBodyBones.LeftHand);
|
||||
endTag = "LeftHand";
|
||||
middleTag = "LeftHint";
|
||||
break;
|
||||
case AvatarIKGoal.RightHand:
|
||||
rootBone = animator.GetBoneTransform(HumanBodyBones.RightUpperArm);
|
||||
middleBone = animator.GetBoneTransform(HumanBodyBones.RightLowerArm);
|
||||
endBone = animator.GetBoneTransform(HumanBodyBones.RightHand);
|
||||
endTag = "RightHand";
|
||||
middleTag = "RightHint";
|
||||
break;
|
||||
case AvatarIKGoal.LeftFoot:
|
||||
rootBone = animator.GetBoneTransform(HumanBodyBones.LeftUpperLeg);
|
||||
middleBone = animator.GetBoneTransform(HumanBodyBones.LeftLowerLeg);
|
||||
endBone = animator.GetBoneTransform(HumanBodyBones.LeftFoot);
|
||||
endTag = "LeftFoot";
|
||||
middleTag = "LeftHint";
|
||||
break;
|
||||
case AvatarIKGoal.RightFoot:
|
||||
rootBone = animator.GetBoneTransform(HumanBodyBones.RightUpperLeg);
|
||||
middleBone = animator.GetBoneTransform(HumanBodyBones.RightLowerLeg);
|
||||
endBone = animator.GetBoneTransform(HumanBodyBones.RightFoot);
|
||||
endTag = "RightFoot";
|
||||
middleTag = "RightHint";
|
||||
break;
|
||||
}
|
||||
}
|
||||
CreateBones();
|
||||
}
|
||||
public bool isValidBones
|
||||
{
|
||||
get
|
||||
{
|
||||
return rootBone &&
|
||||
middleBone &&
|
||||
endBone && endBoneRef &&
|
||||
middleBoneRef &&
|
||||
endBoneOffset &&
|
||||
middleBoneOffset;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void CreateBones()
|
||||
{
|
||||
if (rootTransform && rootBone && middleBone && endBone)
|
||||
{
|
||||
if (!endBoneRef)
|
||||
{
|
||||
endBoneRef = new GameObject(endTag + "Ref").transform;
|
||||
endBoneRef.hideFlags = HideFlags.HideInHierarchy;
|
||||
endBoneRef.SetParent(rootTransform);
|
||||
}
|
||||
if (!middleBoneRef)
|
||||
{
|
||||
middleBoneRef = new GameObject(middleTag + "Ref").transform;
|
||||
middleBoneRef.hideFlags = HideFlags.HideInHierarchy;
|
||||
middleBoneRef.SetParent(rootTransform);
|
||||
}
|
||||
|
||||
if (!endBoneOffset)
|
||||
{
|
||||
endBoneOffset = new GameObject(endTag + "Offset").transform;
|
||||
endBoneOffset.SetParent(endBoneRef);
|
||||
endBoneOffset.localPosition = Vector3.zero;
|
||||
endBoneOffset.localEulerAngles = Vector3.zero;
|
||||
}
|
||||
if (!middleBoneOffset)
|
||||
{
|
||||
middleBoneOffset = new GameObject(middleTag + "Offset").transform;
|
||||
middleBoneOffset.SetParent(middleBoneRef);
|
||||
middleBoneOffset.localPosition = Vector3.zero;
|
||||
middleBoneOffset.localEulerAngles = Vector3.zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get IK Weight
|
||||
/// </summary>
|
||||
public virtual float ikWeight { get { return _weight; } }
|
||||
|
||||
/// <summary>
|
||||
/// Set IK Weight
|
||||
/// </summary>
|
||||
/// <param name="weight"></param>
|
||||
public virtual void SetIKWeight(float weight)
|
||||
{
|
||||
_weight = weight;
|
||||
}
|
||||
|
||||
public void UpdateIK()
|
||||
{
|
||||
if (endBoneRef)
|
||||
{
|
||||
endBoneRef.position = endBone.position;
|
||||
endBoneRef.rotation = endBone.rotation;
|
||||
|
||||
}
|
||||
if (middleBoneRef)
|
||||
{
|
||||
middleBoneRef.position = middleBone.position;
|
||||
middleBoneRef.rotation = middleBone.rotation;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public virtual void AnimationToIK()
|
||||
{
|
||||
if (!isValidBones)
|
||||
{
|
||||
CreateBones();
|
||||
return;
|
||||
}
|
||||
UpdateIK();
|
||||
SetIKHintPosition(middleBoneOffset.position);
|
||||
SetIKPosition(endBoneOffset.position);
|
||||
SetIKRotation(endBoneOffset.rotation);
|
||||
}
|
||||
/// <summary>
|
||||
/// Set IK Position
|
||||
/// </summary>
|
||||
/// <param name="ikPosition"></param>
|
||||
public virtual void SetIKPosition(Vector3 ikPosition)
|
||||
{
|
||||
if (ikWeight <= 0.0f) return;
|
||||
// Calculate middleBone Direction
|
||||
Vector3 middleBoneDirection = Vector3.zero;
|
||||
|
||||
if (hintPosition != null)
|
||||
{
|
||||
// if middleBoneGoal is null, the direction will be calculated with forearm's point
|
||||
middleBoneDirection = (Vector3)hintPosition - rootBone.position;
|
||||
}
|
||||
else
|
||||
{
|
||||
middleBoneDirection = Vector3.Cross(endBone.position - rootBone.position, Vector3.Cross(endBone.position - rootBone.position, endBone.position - middleBone.position));
|
||||
}
|
||||
|
||||
// Get lengths of Arm
|
||||
float rootBoneLength = (middleBone.position - rootBone.position).magnitude;
|
||||
float middleBoneLength = (endBone.position - middleBone.position).magnitude;
|
||||
|
||||
// Calculate the desired middleBone position
|
||||
Vector3 middleBonePos = GetHintPosition(rootBone.position, ikPosition, rootBoneLength, middleBoneLength, middleBoneDirection);
|
||||
|
||||
// Rotate the bone transformations to align correctly
|
||||
Quaternion upperarmRotation = Quaternion.FromToRotation(middleBone.position - rootBone.position, middleBonePos - rootBone.position) * rootBone.rotation;
|
||||
if (!(System.Single.IsNaN(upperarmRotation.x) || System.Single.IsNaN(upperarmRotation.y) || System.Single.IsNaN(upperarmRotation.z)))
|
||||
{
|
||||
//Rotate with transition
|
||||
rootBone.rotation = Quaternion.Slerp(rootBone.rotation, upperarmRotation, ikWeight);
|
||||
Quaternion middleBoneRotation = Quaternion.FromToRotation(endBone.position - middleBone.position, ikPosition - middleBonePos) * middleBone.rotation;
|
||||
middleBone.rotation = Quaternion.Slerp(middleBone.rotation, middleBoneRotation, ikWeight);
|
||||
|
||||
}
|
||||
hintPosition = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set IK Rotation
|
||||
/// </summary>
|
||||
/// <param name="rotation"></param>
|
||||
public virtual void SetIKRotation(Quaternion rotation)
|
||||
{
|
||||
if (!(rootBone && middleBone && endBone) || ikWeight <= 0.0f) return;
|
||||
var _rotation = rotation;
|
||||
|
||||
endBone.rotation = Quaternion.Slerp(endBone.rotation, _rotation, ikWeight);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set IK Hint Position
|
||||
/// ps: Call before SetIKPosition
|
||||
/// </summary>
|
||||
/// <param name="hintPosition"></param>
|
||||
public virtual void SetIKHintPosition(Vector3 hintPosition)
|
||||
{
|
||||
this.hintPosition = hintPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get IK Hint Position
|
||||
/// </summary>
|
||||
/// <param name="rootPos"></param>
|
||||
/// <param name="endPos"></param>
|
||||
/// <param name="rootBoneLength"></param>
|
||||
/// <param name="middleBoneLength"></param>
|
||||
/// <param name="middleBoneDirection"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual Vector3 GetHintPosition(Vector3 rootPos, Vector3 endPos, float rootBoneLength, float middleBoneLength, Vector3 middleBoneDirection)
|
||||
{
|
||||
Vector3 rootToEndDir = endPos - rootPos;
|
||||
float rootToEndMag = rootToEndDir.magnitude;
|
||||
|
||||
float maxDist = (rootBoneLength + middleBoneLength) * 0.999f;
|
||||
if (rootToEndMag > maxDist)
|
||||
{
|
||||
endPos = rootPos + (rootToEndDir.normalized * maxDist);
|
||||
rootToEndDir = endPos - rootPos;
|
||||
rootToEndMag = maxDist;
|
||||
}
|
||||
|
||||
float minDist = Mathf.Abs(rootBoneLength - middleBoneLength) * 1.001f;
|
||||
if (rootToEndMag < minDist)
|
||||
{
|
||||
endPos = rootPos + (rootToEndDir.normalized * minDist);
|
||||
rootToEndDir = endPos - rootPos;
|
||||
rootToEndMag = minDist;
|
||||
}
|
||||
|
||||
float aa = ((rootToEndMag * rootToEndMag + rootBoneLength * rootBoneLength - middleBoneLength * middleBoneLength) * 0.5f) / rootToEndMag;
|
||||
float bb = Mathf.Sqrt(rootBoneLength * rootBoneLength - aa * aa);
|
||||
Vector3 crossElbow = Vector3.Cross(rootToEndDir, Vector3.Cross(middleBoneDirection, rootToEndDir));
|
||||
return rootPos + (aa * rootToEndDir.normalized) + (bb * crossElbow.normalized);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f2b3ca9b2c658a47b99571d9f96e74d
|
||||
timeCreated: 1541778644
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user