using System; using UnityEngine; namespace RootMotion.FinalIK { [Serializable] public class IKMapping { [Serializable] public class BoneMap { public Transform transform; public int chainIndex = -1; public int nodeIndex = -1; public Vector3 defaultLocalPosition; public Quaternion defaultLocalRotation; public Vector3 localSwingAxis; public Vector3 localTwistAxis; public Vector3 planePosition; public Vector3 ikPosition; public Quaternion defaultLocalTargetRotation; private Quaternion maintainRotation; public float length; public Quaternion animatedRotation; private Transform planeBone1; private Transform planeBone2; private Transform planeBone3; private int plane1ChainIndex = -1; private int plane1NodeIndex = -1; private int plane2ChainIndex = -1; private int plane2NodeIndex = -1; private int plane3ChainIndex = -1; private int plane3NodeIndex = -1; public Vector3 swingDirection => transform.rotation * localSwingAxis; public bool isNodeBone => nodeIndex != -1; private Quaternion lastAnimatedTargetRotation { get { if (planeBone1.position == planeBone3.position) { return Quaternion.identity; } return Quaternion.LookRotation(planeBone2.position - planeBone1.position, planeBone3.position - planeBone1.position); } } public void Initiate(Transform transform, IKSolverFullBody solver) { this.transform = transform; solver.GetChainAndNodeIndexes(transform, out chainIndex, out nodeIndex); } public void StoreDefaultLocalState() { defaultLocalPosition = transform.localPosition; defaultLocalRotation = transform.localRotation; } public void FixTransform(bool position) { if (position) { transform.localPosition = defaultLocalPosition; } transform.localRotation = defaultLocalRotation; } public void SetLength(BoneMap nextBone) { length = Vector3.Distance(transform.position, nextBone.transform.position); } public void SetLocalSwingAxis(BoneMap swingTarget) { SetLocalSwingAxis(swingTarget, this); } public void SetLocalSwingAxis(BoneMap bone1, BoneMap bone2) { localSwingAxis = Quaternion.Inverse(transform.rotation) * (bone1.transform.position - bone2.transform.position); } public void SetLocalTwistAxis(Vector3 twistDirection, Vector3 normalDirection) { Vector3.OrthoNormalize(ref normalDirection, ref twistDirection); localTwistAxis = Quaternion.Inverse(transform.rotation) * twistDirection; } public void SetPlane(IKSolverFullBody solver, Transform planeBone1, Transform planeBone2, Transform planeBone3) { this.planeBone1 = planeBone1; this.planeBone2 = planeBone2; this.planeBone3 = planeBone3; solver.GetChainAndNodeIndexes(planeBone1, out plane1ChainIndex, out plane1NodeIndex); solver.GetChainAndNodeIndexes(planeBone2, out plane2ChainIndex, out plane2NodeIndex); solver.GetChainAndNodeIndexes(planeBone3, out plane3ChainIndex, out plane3NodeIndex); UpdatePlane(rotation: true, position: true); } public void UpdatePlane(bool rotation, bool position) { Quaternion rotation2 = lastAnimatedTargetRotation; if (rotation) { defaultLocalTargetRotation = QuaTools.RotationToLocalSpace(transform.rotation, rotation2); } if (position) { planePosition = Quaternion.Inverse(rotation2) * (transform.position - planeBone1.position); } } public void SetIKPosition() { ikPosition = transform.position; } public void MaintainRotation() { maintainRotation = transform.rotation; } public void SetToIKPosition() { transform.position = ikPosition; } public void FixToNode(IKSolverFullBody solver, float weight, IKSolver.Node fixNode = null) { if (fixNode == null) { fixNode = solver.GetNode(chainIndex, nodeIndex); } if (weight >= 1f) { transform.position = fixNode.solverPosition; } else { transform.position = Vector3.Lerp(transform.position, fixNode.solverPosition, weight); } } public Vector3 GetPlanePosition(IKSolverFullBody solver) { return solver.GetNode(plane1ChainIndex, plane1NodeIndex).solverPosition + GetTargetRotation(solver) * planePosition; } public void PositionToPlane(IKSolverFullBody solver) { transform.position = GetPlanePosition(solver); } public void RotateToPlane(IKSolverFullBody solver, float weight) { Quaternion quaternion = GetTargetRotation(solver) * defaultLocalTargetRotation; if (weight >= 1f) { transform.rotation = quaternion; } else { transform.rotation = Quaternion.Lerp(transform.rotation, quaternion, weight); } } public void Swing(Vector3 swingTarget, float weight) { Swing(swingTarget, transform.position, weight); } public void Swing(Vector3 pos1, Vector3 pos2, float weight) { Quaternion quaternion = Quaternion.FromToRotation(transform.rotation * localSwingAxis, pos1 - pos2) * transform.rotation; if (weight >= 1f) { transform.rotation = quaternion; } else { transform.rotation = Quaternion.Lerp(transform.rotation, quaternion, weight); } } public void Twist(Vector3 twistDirection, Vector3 normalDirection, float weight) { Vector3.OrthoNormalize(ref normalDirection, ref twistDirection); Quaternion quaternion = Quaternion.FromToRotation(transform.rotation * localTwistAxis, twistDirection) * transform.rotation; if (weight >= 1f) { transform.rotation = quaternion; } else { transform.rotation = Quaternion.Lerp(transform.rotation, quaternion, weight); } } public void RotateToMaintain(float weight) { if (!(weight <= 0f)) { transform.rotation = Quaternion.Lerp(transform.rotation, maintainRotation, weight); } } public void RotateToEffector(IKSolverFullBody solver, float weight) { if (!isNodeBone) { return; } float num = weight * solver.GetNode(chainIndex, nodeIndex).effectorRotationWeight; if (!(num <= 0f)) { if (num >= 1f) { transform.rotation = solver.GetNode(chainIndex, nodeIndex).solverRotation; } else { transform.rotation = Quaternion.Lerp(transform.rotation, solver.GetNode(chainIndex, nodeIndex).solverRotation, num); } } } private Quaternion GetTargetRotation(IKSolverFullBody solver) { Vector3 solverPosition = solver.GetNode(plane1ChainIndex, plane1NodeIndex).solverPosition; Vector3 solverPosition2 = solver.GetNode(plane2ChainIndex, plane2NodeIndex).solverPosition; Vector3 solverPosition3 = solver.GetNode(plane3ChainIndex, plane3NodeIndex).solverPosition; if (solverPosition == solverPosition3) { return Quaternion.identity; } return Quaternion.LookRotation(solverPosition2 - solverPosition, solverPosition3 - solverPosition); } } public virtual bool IsValid(IKSolver solver, ref string message) { return true; } public virtual void Initiate(IKSolverFullBody solver) { } protected bool BoneIsValid(Transform bone, IKSolver solver, ref string message, Warning.Logger logger = null) { if (bone == null) { message = "IKMappingLimb contains a null reference."; logger?.Invoke(message); return false; } if (solver.GetPoint(bone) == null) { message = "IKMappingLimb is referencing to a bone '" + bone.name + "' that does not excist in the Node Chain."; logger?.Invoke(message); return false; } return true; } protected Vector3 SolveFABRIKJoint(Vector3 pos1, Vector3 pos2, float length) { return pos2 + (pos1 - pos2).normalized * length; } } }