public void AutoSetup() { if (AutoSetupEndJoint == null) { return; } var joints = new List <Transform>(); joints = AddIntermediateObjects(joints); if (EndOffset) { joints = AddEndOffset(joints); } var ikParent = GameObject.Find("_IkControllers"); if (ikParent == null) { ikParent = new GameObject { name = "_IkControllers" } } ; Chain = new RageIkChain(joints, ikParent.transform, TwoDmode); Chain.Init(); Chain.Target = CreateController(ikParent, joints[joints.Count - 1].gameObject, "IkTarget_" + gameObject.name).transform; SetupJointLimiters(Chain); }
private static void BackwardReachingPhase(RageIkChain chain, Vector3[] desiredPositions, Vector3 rootInitial) { desiredPositions[0] = rootInitial; for (int i = 0; i < chain.Joints.Count - 1; i++) { float lambda = chain.SegmentLengths[i] / Vector3.Distance(desiredPositions[i + 1], desiredPositions[i]); desiredPositions[i + 1] = (1 - lambda) * desiredPositions[i] + lambda * desiredPositions[i + 1]; Quaternion rotation = Quaternion.FromToRotation(chain.Joints[i + 1].position - chain.Joints[i].position, desiredPositions[i + 1] - chain.Joints[i].position); AddRotation(chain.Joints[i], rotation, chain); var limiter = chain.Joints[i].GetComponent <RageIkJointLimiter>(); if (limiter == null) { continue; } if (limiter.ValidVector(limiter.RestDirection)) { continue; } if (Vector3.Angle(limiter.RestDirection, limiter.MaxAngle) > Vector3.Angle(limiter.RestDirection, limiter.MinAngle)) { RotateToLimit(chain, desiredPositions, i, limiter.RestDirection, limiter.MinAngle); continue; } RotateToLimit(chain, desiredPositions, i, limiter.RestDirection, limiter.MaxAngle); } ChangeLastElementRotation(chain); }
/// <summary> Sets up Joint Limiter components (if none found) and values for all joints</summary> private void SetupJointLimiters(RageIkChain chain) { int lastJoint = EndOffset ? (chain.Joints.Count - 1) : chain.Joints.Count; for (int i = 0; i < lastJoint; i++) { var thisJoint = chain.Joints[i]; var jointLimiter = thisJoint.GetComponent <RageIkJointLimiter>(); if (jointLimiter == null && !JointLimiterLive) { continue; } if (jointLimiter == null) { jointLimiter = thisJoint.gameObject.AddComponent <RageIkJointLimiter>(); } jointLimiter.Live = JointLimiterLive; Transform childTransform = GetValidChild(chain.Joints[i], AutoSetupEndJoint); if (childTransform == null) { childTransform = chain.Target; } var deltaVector = childTransform.position - chain.Joints[i].position; jointLimiter.RestAngle = jointLimiter.GetRestDirectionAngle(deltaVector); jointLimiter.MinAngle = jointLimiter.MaxAngle = deltaVector; jointLimiter.MinLimiterAngle -= JointLimiterAngleDelta; jointLimiter.MaxLimiterAngle += JointLimiterAngleDelta; } }
private static void ChangeLastElementRotation(RageIkChain chain) { if (!chain.AlignEnd) { return; } Transform lastElement = (chain.Joints[chain.Joints.Count - 1].name == "endOffset") ? chain.Joints[chain.Joints.Count - 2] : chain.Joints[chain.Joints.Count - 1]; Quaternion lastElementRotation = chain.Target.rotation; SetRotation(lastElement, lastElementRotation, chain); var lastElementLimiter = lastElement.GetComponent <RageIkJointLimiter>(); if (lastElementLimiter == null) { return; } if (lastElementLimiter.ValidVector(lastElementLimiter.RestDirection)) { return; } if (Vector3.Angle(lastElementLimiter.RestDirection, lastElementLimiter.MaxAngle) > Vector3.Angle(lastElementLimiter.RestDirection, lastElementLimiter.MinAngle)) { AddRotation(lastElement, Quaternion.FromToRotation(lastElementLimiter.RestDirection, lastElementLimiter.MinAngle), chain, false); return; } AddRotation(lastElement, Quaternion.FromToRotation(lastElementLimiter.RestDirection, lastElementLimiter.MaxAngle), chain); }
private static void RotateToLimit(RageIkChain chain, Vector3[] desiredPositions, int idx, Vector3 fromDirection, Vector3 toDirection) { var rotation = Quaternion.FromToRotation(fromDirection, toDirection); AddRotation(chain.Joints[idx], rotation, chain, false); desiredPositions[idx + 1] = chain.Joints[idx + 1].position; }
public static void Solve(RageIkChain chain) { if (chain.Joints.Count < 2) { return; } chain.Init(); if (IsTargetUnreachable(chain)) { for (int i = 0; i < chain.Joints.Count - 1; i++) { Quaternion rotation = Quaternion.FromToRotation(chain.Joints[i + 1].position - chain.Joints[i].position, chain.Target.position - chain.Joints[i].position); AddRotation(chain.Joints[i], rotation, chain); var limiter = chain.Joints[i].GetComponent <RageIkJointLimiter>(); if (limiter == null || !limiter.Live) { continue; } if (limiter.ValidVector(limiter.RestDirection)) { continue; } if (Vector3.Angle(limiter.RestDirection, limiter.MaxAngle) > Vector3.Angle(limiter.RestDirection, limiter.MinAngle)) { AddRotation(chain.Joints[i], Quaternion.FromToRotation(limiter.RestDirection, limiter.MinAngle), chain); continue; } AddRotation(chain.Joints[i], Quaternion.FromToRotation(limiter.RestDirection, limiter.MaxAngle), chain); } ChangeLastElementRotation(chain); return; } int tries = 0; Vector3 rootInitial = chain.Joints[0].position; float targetDelta = Vector3.Distance(chain.Joints[chain.Joints.Count - 1].position, chain.Target.position); var desiredPositions = new Vector3[chain.Joints.Count]; for (int i = 0; i < chain.Joints.Count; i++) { desiredPositions[i] = chain.Joints[i].position; } while (targetDelta > Accuracy && tries < MaxIterations) { ForwardReachingPhase(chain, desiredPositions); BackwardReachingPhase(chain, desiredPositions, rootInitial); targetDelta = Vector3.Distance(desiredPositions[chain.Joints.Count - 1], chain.Target.position); tries++; } }
private static void ForwardReachingPhase(RageIkChain chain, Vector3[] desiredPositions) { desiredPositions[chain.Joints.Count - 1] = chain.Target.position; for (int i = desiredPositions.Length - 2; i > 0; i--) { float lambda = chain.SegmentLengths[i] / Vector3.Distance(desiredPositions[i + 1], desiredPositions[i]); desiredPositions[i] = (1 - lambda) * desiredPositions[i + 1] + lambda * desiredPositions[i]; } }
private static void SetRotation(Transform joint, Quaternion rotation, RageIkChain chain, bool smoothRotations = true) { if (chain.TwoDeeMode) { var smoothRotation = rotation; if (smoothRotations && chain.Snap < 1f) { smoothRotation = Quaternion.Slerp(joint.rotation, rotation, Time.deltaTime * chain.Snap); } joint.eulerAngles = new Vector3(0, 0, smoothRotation.eulerAngles.z); return; } joint.rotation = rotation; }
private static bool IsTargetUnreachable(RageIkChain chain) { float rootToTargetDist = Vector3.Distance(chain.Joints[0].position, chain.Target.position); return(rootToTargetDist > chain.Length); }
private static void AddRotation(Transform joint, Quaternion rotation, RageIkChain chain, bool smoothRotations = true) { SetRotation(joint, rotation * joint.rotation, chain, smoothRotations); }