testss
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
using UnityEngine.Scripting.APIUpdating;
|
||||
|
||||
namespace UnityEngine.U2D.IK
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility for 2D based Cyclic Coordinate Descent (CCD) IK Solver.
|
||||
/// </summary>
|
||||
[MovedFrom("UnityEngine.Experimental.U2D.IK")]
|
||||
public static class CCD2D
|
||||
{
|
||||
/// <summary>
|
||||
/// Solve IK Chain based on CCD.
|
||||
/// </summary>
|
||||
/// <param name="targetPosition">Target position.</param>
|
||||
/// <param name="forward">Forward vector for solver.</param>
|
||||
/// <param name="solverLimit">Solver iteration count.</param>
|
||||
/// <param name="tolerance">Target position's tolerance.</param>
|
||||
/// <param name="velocity">Velocity towards target position.</param>
|
||||
/// <param name="positions">Chain positions.</param>
|
||||
/// <returns>Returns true if solver successfully completes within iteration limit. False otherwise.</returns>
|
||||
public static bool Solve(Vector3 targetPosition, Vector3 forward, int solverLimit, float tolerance, float velocity, ref Vector3[] positions)
|
||||
{
|
||||
int last = positions.Length - 1;
|
||||
int iterations = 0;
|
||||
float sqrTolerance = tolerance * tolerance;
|
||||
float sqrDistanceToTarget = (targetPosition - positions[last]).sqrMagnitude;
|
||||
while (sqrDistanceToTarget > sqrTolerance)
|
||||
{
|
||||
DoIteration(targetPosition, forward, last, velocity, ref positions);
|
||||
sqrDistanceToTarget = (targetPosition - positions[last]).sqrMagnitude;
|
||||
if (++iterations >= solverLimit)
|
||||
break;
|
||||
}
|
||||
return iterations != 0;
|
||||
}
|
||||
|
||||
static void DoIteration(Vector3 targetPosition, Vector3 forward, int last, float velocity, ref Vector3[] positions)
|
||||
{
|
||||
for (int i = last - 1; i >= 0; --i)
|
||||
{
|
||||
Vector3 toTarget = targetPosition - positions[i];
|
||||
Vector3 toLast = positions[last] - positions[i];
|
||||
|
||||
float angle = Vector3.SignedAngle(toLast, toTarget, forward);
|
||||
angle = Mathf.Lerp(0f, angle, velocity);
|
||||
|
||||
Quaternion deltaRotation = Quaternion.AngleAxis(angle, forward);
|
||||
for (int j = last; j > i; --j)
|
||||
positions[j] = RotatePositionFrom(positions[j], positions[i], deltaRotation);
|
||||
}
|
||||
}
|
||||
|
||||
static Vector3 RotatePositionFrom(Vector3 position, Vector3 pivot, Quaternion rotation)
|
||||
{
|
||||
Vector3 v = position - pivot;
|
||||
v = rotation * v;
|
||||
return pivot + v;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,171 @@
|
||||
using UnityEngine.Scripting.APIUpdating;
|
||||
|
||||
namespace UnityEngine.U2D.IK
|
||||
{
|
||||
/// <summary>
|
||||
/// Structure to store FABRIK Chain data.
|
||||
/// </summary>
|
||||
[MovedFrom("UnityEngine.Experimental.U2D.IK")]
|
||||
public struct FABRIKChain2D
|
||||
{
|
||||
public Vector2 first
|
||||
{
|
||||
get { return positions[0]; }
|
||||
}
|
||||
|
||||
public Vector2 last
|
||||
{
|
||||
get { return positions[positions.Length - 1]; }
|
||||
}
|
||||
|
||||
public Vector2 origin;
|
||||
public Vector2 target;
|
||||
public float sqrTolerance;
|
||||
public Vector2[] positions;
|
||||
public float[] lengths;
|
||||
public int[] subChainIndices;
|
||||
public Vector3[] worldPositions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utility for 2D Forward And Backward Reaching Inverse Kinematics (FABRIK) IK Solver.
|
||||
/// </summary>
|
||||
public static class FABRIK2D
|
||||
{
|
||||
/// <summary>
|
||||
/// Solve IK based on FABRIK
|
||||
/// </summary>
|
||||
/// <param name="targetPosition">Target position.</param>
|
||||
/// <param name="solverLimit">Solver iteration count.</param>
|
||||
/// <param name="tolerance">Target position's tolerance.</param>
|
||||
/// <param name="lengths">Length of the chains.</param>
|
||||
/// <param name="positions">Chain positions.</param>
|
||||
/// <returns>Returns true if solver successfully completes within iteration limit. False otherwise.</returns>
|
||||
public static bool Solve(Vector2 targetPosition, int solverLimit, float tolerance, float[] lengths, ref Vector2[] positions)
|
||||
{
|
||||
int last = positions.Length - 1;
|
||||
int iterations = 0;
|
||||
float sqrTolerance = tolerance * tolerance;
|
||||
float sqrDistanceToTarget = (targetPosition - positions[last]).sqrMagnitude;
|
||||
Vector2 originPosition = positions[0];
|
||||
while (sqrDistanceToTarget > sqrTolerance)
|
||||
{
|
||||
Forward(targetPosition, lengths, ref positions);
|
||||
Backward(originPosition, lengths, ref positions);
|
||||
sqrDistanceToTarget = (targetPosition - positions[last]).sqrMagnitude;
|
||||
if (++iterations >= solverLimit)
|
||||
break;
|
||||
}
|
||||
|
||||
// Return whether positions have changed
|
||||
return iterations != 0;
|
||||
}
|
||||
|
||||
public static bool SolveChain(int solverLimit, ref FABRIKChain2D[] chains)
|
||||
{
|
||||
// Do a quick validation of the end points that it has not been solved
|
||||
if (ValidateChain(chains))
|
||||
return false;
|
||||
|
||||
// Validation failed, solve chain
|
||||
for (int iterations = 0; iterations < solverLimit; ++iterations)
|
||||
{
|
||||
SolveForwardsChain(0, ref chains);
|
||||
// Break if solution is solved
|
||||
if (!SolveBackwardsChain(0, ref chains))
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ValidateChain(FABRIKChain2D[] chains)
|
||||
{
|
||||
foreach (var chain in chains)
|
||||
{
|
||||
if (chain.subChainIndices.Length == 0 && (chain.target - chain.last).sqrMagnitude > chain.sqrTolerance)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void SolveForwardsChain(int idx, ref FABRIKChain2D[] chains)
|
||||
{
|
||||
var target = chains[idx].target;
|
||||
if (chains[idx].subChainIndices.Length > 0)
|
||||
{
|
||||
target = Vector2.zero;
|
||||
for (int i = 0; i < chains[idx].subChainIndices.Length; ++i)
|
||||
{
|
||||
var childIdx = chains[idx].subChainIndices[i];
|
||||
SolveForwardsChain(childIdx, ref chains);
|
||||
target += chains[childIdx].first;
|
||||
}
|
||||
target = target / chains[idx].subChainIndices.Length;
|
||||
}
|
||||
Forward(target, chains[idx].lengths, ref chains[idx].positions);
|
||||
}
|
||||
|
||||
static bool SolveBackwardsChain(int idx, ref FABRIKChain2D[] chains)
|
||||
{
|
||||
bool notSolved = false;
|
||||
Backward(chains[idx].origin, chains[idx].lengths, ref chains[idx].positions);
|
||||
for (int i = 0; i < chains[idx].subChainIndices.Length; ++i)
|
||||
{
|
||||
var childIdx = chains[idx].subChainIndices[i];
|
||||
chains[childIdx].origin = chains[idx].last;
|
||||
notSolved |= SolveBackwardsChain(childIdx, ref chains);
|
||||
}
|
||||
// Check if end point has reached the target
|
||||
if (chains[idx].subChainIndices.Length == 0)
|
||||
{
|
||||
notSolved |= (chains[idx].target - chains[idx].last).sqrMagnitude > chains[idx].sqrTolerance;
|
||||
}
|
||||
return notSolved;
|
||||
}
|
||||
|
||||
static void Forward(Vector2 targetPosition, float[] lengths, ref Vector2[] positions)
|
||||
{
|
||||
var last = positions.Length - 1;
|
||||
positions[last] = targetPosition;
|
||||
for (int i = last - 1; i >= 0; --i)
|
||||
{
|
||||
var r = positions[i + 1] - positions[i];
|
||||
var l = lengths[i] / r.magnitude;
|
||||
var position = (1f - l) * positions[i + 1] + l * positions[i];
|
||||
positions[i] = position;
|
||||
}
|
||||
}
|
||||
|
||||
static void Backward(Vector2 originPosition, float[] lengths, ref Vector2[] positions)
|
||||
{
|
||||
positions[0] = originPosition;
|
||||
var last = positions.Length - 1;
|
||||
for (int i = 0; i < last; ++i)
|
||||
{
|
||||
var r = positions[i + 1] - positions[i];
|
||||
var l = lengths[i] / r.magnitude;
|
||||
var position = (1f - l) * positions[i] + l * positions[i + 1];
|
||||
positions[i + 1] = position;
|
||||
}
|
||||
}
|
||||
|
||||
// For constraints
|
||||
static Vector2 ValidateJoint(Vector2 endPosition, Vector2 startPosition, Vector2 right, float min, float max)
|
||||
{
|
||||
var localDifference = endPosition - startPosition;
|
||||
var angle = Vector2.SignedAngle(right, localDifference);
|
||||
var validatedPosition = endPosition;
|
||||
if (angle < min)
|
||||
{
|
||||
var minRotation = Quaternion.Euler(0f, 0f, min);
|
||||
validatedPosition = startPosition + (Vector2)(minRotation * right * localDifference.magnitude);
|
||||
}
|
||||
else if (angle > max)
|
||||
{
|
||||
var maxRotation = Quaternion.Euler(0f, 0f, max);
|
||||
validatedPosition = startPosition + (Vector2)(maxRotation * right * localDifference.magnitude);
|
||||
}
|
||||
return validatedPosition;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
using UnityEngine.Scripting.APIUpdating;
|
||||
|
||||
namespace UnityEngine.U2D.IK
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility for 2D Limb IK Solver.
|
||||
/// </summary>
|
||||
[MovedFrom("UnityEngine.Experimental.U2D.IK")]
|
||||
public static class Limb
|
||||
{
|
||||
/// <summary>
|
||||
/// Solve based on Limb IK
|
||||
/// </summary>
|
||||
/// <param name="targetPosition">Target position.</param>
|
||||
/// <param name="lengths">Length of the chains.</param>
|
||||
/// <param name="positions">Chain positions.</param>
|
||||
/// <param name="outAngles">Output angles for the chain's position.</param>
|
||||
/// <returns>Always returns true.</returns>
|
||||
public static bool Solve(Vector3 targetPosition, float[] lengths, Vector3[] positions, ref float[] outAngles)
|
||||
{
|
||||
outAngles[0] = 0f;
|
||||
outAngles[1] = 0f;
|
||||
|
||||
if (lengths[0] == 0f || lengths[1] == 0f)
|
||||
return false;
|
||||
|
||||
Vector3 startToEnd = targetPosition - positions[0];
|
||||
float distanceMagnitude = startToEnd.magnitude;
|
||||
float sqrDistance = startToEnd.sqrMagnitude;
|
||||
|
||||
float sqrParentLength = (lengths[0] * lengths[0]);
|
||||
float sqrTargetLength = (lengths[1] * lengths[1]);
|
||||
|
||||
float angle0Cos = (sqrDistance + sqrParentLength - sqrTargetLength) / (2f * lengths[0] * distanceMagnitude);
|
||||
float angle1Cos = (sqrDistance - sqrParentLength - sqrTargetLength) / (2f * lengths[0] * lengths[1]);
|
||||
|
||||
if ((angle0Cos >= -1f && angle0Cos <= 1f) && (angle1Cos >= -1f && angle1Cos <= 1f))
|
||||
{
|
||||
outAngles[0] = Mathf.Acos(angle0Cos) * Mathf.Rad2Deg;
|
||||
outAngles[1] = Mathf.Acos(angle1Cos) * Mathf.Rad2Deg;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user