first commit

This commit is contained in:
lethanhsonvsp
2025-11-17 15:16:36 +07:00
commit a40d0921eb
17012 changed files with 2652386 additions and 0 deletions

View File

@@ -0,0 +1,114 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// Rigid transform with only translation and rotation components.
/// </summary>
[System.Serializable]
public struct AffineTransform
{
/// <summary>Translation component of the AffineTransform.</summary>
public Vector3 translation;
/// <summary>Rotation component of the AffineTransform.</summary>
public Quaternion rotation;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="t">Translation component of the AffineTransform.</param>
/// <param name="r">Rotation component of the AffineTransform.</param>
public AffineTransform(Vector3 t, Quaternion r)
{
translation = t;
rotation = r;
}
/// <summary>
/// Sets the translation and rotation in the AffineTransform.
/// </summary>
/// <param name="t">Translation component of the AffineTransform.</param>
/// <param name="r">Rotation component of the AffineTransform.</param>
public void Set(Vector3 t, Quaternion r)
{
translation = t;
rotation = r;
}
/// <summary>
/// Transforms a Vector3 point by the AffineTransform.
/// </summary>
/// <param name="p">Vector3 point.</param>
/// <returns>Transformed Vector3 point.</returns>
public Vector3 Transform(Vector3 p) =>
rotation * p + translation;
/// <summary>
/// Transforms a Vector3 point by the inverse of the AffineTransform.
/// </summary>
/// <param name="p">Vector3 point.</param>
/// <returns>Transformed Vector3 point.</returns>
public Vector3 InverseTransform(Vector3 p) =>
Quaternion.Inverse(rotation) * (p - translation);
/// <summary>
/// Calculates the inverse of the AffineTransform.
/// </summary>
/// <returns>The inverse of the AffineTransform.</returns>
public AffineTransform Inverse()
{
var invR = Quaternion.Inverse(rotation);
return new AffineTransform(invR * -translation, invR);
}
/// <summary>
/// Multiply a transform by the inverse of the AffineTransform.
/// </summary>
/// <param name="transform">AffineTransform value.</param>
/// <returns>Multiplied AffineTransform result.</returns>
public AffineTransform InverseMul(AffineTransform transform)
{
var invR = Quaternion.Inverse(rotation);
return new AffineTransform(invR * (transform.translation - translation), invR * transform.rotation);
}
/// <summary>
/// Transforms a Vector3 point by the AffineTransform.
/// </summary>
/// <param name="lhs">AffineTransform value.</param>
/// <param name="rhs">Vector3 point.</param>
/// <returns>Transformed Vector3 point.</returns>
public static Vector3 operator *(AffineTransform lhs, Vector3 rhs) =>
lhs.rotation * rhs + lhs.translation;
/// <summary>
/// Multiplies two AffineTransform.
/// </summary>
/// <param name="lhs">First AffineTransform value.</param>
/// <param name="rhs">Second AffineTransform value.</param>
/// <returns>Multiplied AffineTransform result.</returns>
public static AffineTransform operator *(AffineTransform lhs, AffineTransform rhs) =>
new AffineTransform(lhs.Transform(rhs.translation), lhs.rotation * rhs.rotation);
/// <summary>
/// Rotates an AffineTransform.
/// </summary>
/// <param name="lhs">Quaternion rotation.</param>
/// <param name="rhs">AffineTransform value.</param>
/// <returns>Rotated AffineTransform result.</returns>
public static AffineTransform operator *(Quaternion lhs, AffineTransform rhs) =>
new AffineTransform(lhs * rhs.translation, lhs * rhs.rotation);
/// <summary>
/// Transforms a Quaternion value by the AffineTransform.
/// </summary>
/// <param name="lhs">AffineTransform value.</param>
/// <param name="rhs">Quaternion rotation.</param>
/// <returns>Transformed AffineTransform result.</returns>
public static AffineTransform operator *(AffineTransform lhs, Quaternion rhs) =>
new AffineTransform(lhs.translation, lhs.rotation * rhs);
/// <summary>
/// AffineTransform identity value.
/// </summary>
public static AffineTransform identity { get; } = new AffineTransform(Vector3.zero, Quaternion.identity);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d9baa6934219a6645a3f6830ee9960fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,397 @@
using Unity.Collections;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// Utility functions for runtime constraints.
/// </summary>
public static class AnimationRuntimeUtils
{
const float k_SqrEpsilon = 1e-8f;
/// <summary>
/// Evaluates the Two-Bone IK algorithm.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
/// <param name="root">The transform handle for the root transform.</param>
/// <param name="mid">The transform handle for the mid transform.</param>
/// <param name="tip">The transform handle for the tip transform.</param>
/// <param name="target">The transform handle for the target transform.</param>
/// <param name="hint">The transform handle for the hint transform.</param>
/// <param name="posWeight">The weight for which target position has an effect on IK calculations. This is a value in between 0 and 1.</param>
/// <param name="rotWeight">The weight for which target rotation has an effect on IK calculations. This is a value in between 0 and 1.</param>
/// <param name="hintWeight">The weight for which hint transform has an effect on IK calculations. This is a value in between 0 and 1.</param>
/// <param name="targetOffset">The offset applied to the target transform.</param>
public static void SolveTwoBoneIK(
AnimationStream stream,
ReadWriteTransformHandle root,
ReadWriteTransformHandle mid,
ReadWriteTransformHandle tip,
ReadOnlyTransformHandle target,
ReadOnlyTransformHandle hint,
float posWeight,
float rotWeight,
float hintWeight,
AffineTransform targetOffset
)
{
Vector3 aPosition = root.GetPosition(stream);
Vector3 bPosition = mid.GetPosition(stream);
Vector3 cPosition = tip.GetPosition(stream);
target.GetGlobalTR(stream, out Vector3 targetPos, out Quaternion targetRot);
Vector3 tPosition = Vector3.Lerp(cPosition, targetPos + targetOffset.translation, posWeight);
Quaternion tRotation = Quaternion.Lerp(tip.GetRotation(stream), targetRot * targetOffset.rotation, rotWeight);
bool hasHint = hint.IsValid(stream) && hintWeight > 0f;
Vector3 ab = bPosition - aPosition;
Vector3 bc = cPosition - bPosition;
Vector3 ac = cPosition - aPosition;
Vector3 at = tPosition - aPosition;
float abLen = ab.magnitude;
float bcLen = bc.magnitude;
float acLen = ac.magnitude;
float atLen = at.magnitude;
float oldAbcAngle = TriangleAngle(acLen, abLen, bcLen);
float newAbcAngle = TriangleAngle(atLen, abLen, bcLen);
// Bend normal strategy is to take whatever has been provided in the animation
// stream to minimize configuration changes, however if this is collinear
// try computing a bend normal given the desired target position.
// If this also fails, try resolving axis using hint if provided.
Vector3 axis = Vector3.Cross(ab, bc);
if (axis.sqrMagnitude < k_SqrEpsilon)
{
axis = hasHint ? Vector3.Cross(hint.GetPosition(stream) - aPosition, bc) : Vector3.zero;
if (axis.sqrMagnitude < k_SqrEpsilon)
axis = Vector3.Cross(at, bc);
if (axis.sqrMagnitude < k_SqrEpsilon)
axis = Vector3.up;
}
axis = Vector3.Normalize(axis);
float a = 0.5f * (oldAbcAngle - newAbcAngle);
float sin = Mathf.Sin(a);
float cos = Mathf.Cos(a);
Quaternion deltaR = new Quaternion(axis.x * sin, axis.y * sin, axis.z * sin, cos);
mid.SetRotation(stream, deltaR * mid.GetRotation(stream));
cPosition = tip.GetPosition(stream);
ac = cPosition - aPosition;
root.SetRotation(stream, QuaternionExt.FromToRotation(ac, at) * root.GetRotation(stream));
if (hasHint)
{
float acSqrMag = ac.sqrMagnitude;
if (acSqrMag > 0f)
{
bPosition = mid.GetPosition(stream);
cPosition = tip.GetPosition(stream);
ab = bPosition - aPosition;
ac = cPosition - aPosition;
Vector3 acNorm = ac / Mathf.Sqrt(acSqrMag);
Vector3 ah = hint.GetPosition(stream) - aPosition;
Vector3 abProj = ab - acNorm * Vector3.Dot(ab, acNorm);
Vector3 ahProj = ah - acNorm * Vector3.Dot(ah, acNorm);
float maxReach = abLen + bcLen;
if (abProj.sqrMagnitude > (maxReach * maxReach * 0.001f) && ahProj.sqrMagnitude > 0f)
{
Quaternion hintR = QuaternionExt.FromToRotation(abProj, ahProj);
hintR.x *= hintWeight;
hintR.y *= hintWeight;
hintR.z *= hintWeight;
hintR = QuaternionExt.NormalizeSafe(hintR);
root.SetRotation(stream, hintR * root.GetRotation(stream));
}
}
}
tip.SetRotation(stream, tRotation);
}
/// <summary>
/// Sets the position for a hint and target given bone positions.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
/// <param name="root">The transform handle for the root transform.</param>
/// <param name="mid">The transform handle for the mid transform.</param>
/// <param name="tip">The transform handle for the tip transform.</param>
/// <param name="target">The transform handle for the target transform.</param>
/// <param name="hint">The transform handle for the hint transform.</param>
/// <param name="posWeight">The weight for which target position has an effect on IK calculations. This is a value in between 0 and 1.</param>
/// <param name="rotWeight">The weight for which target rotation has an effect on IK calculations. This is a value in between 0 and 1.</param>
/// <param name="hintWeight">The weight for which hint transform has an effect on IK calculations. This is a value in between 0 and 1.</param>
/// <param name="targetOffset">The offset applied to the target transform.</param>
public static void InverseSolveTwoBoneIK(
AnimationStream stream,
ReadOnlyTransformHandle root,
ReadOnlyTransformHandle mid,
ReadOnlyTransformHandle tip,
ReadWriteTransformHandle target,
ReadWriteTransformHandle hint,
float posWeight,
float rotWeight,
float hintWeight,
AffineTransform targetOffset
)
{
Vector3 rootPosition = root.GetPosition(stream);
Vector3 midPosition = mid.GetPosition(stream);
tip.GetGlobalTR(stream, out var tipPosition, out var tipRotation);
target.GetGlobalTR(stream, out var targetPosition, out var targetRotation);
bool isHintValid = hint.IsValid(stream);
Vector3 hintPosition = Vector3.zero;
if(isHintValid)
hintPosition = hint.GetPosition(stream);
InverseSolveTwoBoneIK(rootPosition, midPosition, tipPosition, tipRotation, ref targetPosition,
ref targetRotation, ref hintPosition, isHintValid, posWeight, rotWeight, hintWeight, targetOffset);
target.SetPosition(stream, targetPosition);
target.SetRotation(stream, targetRotation);
hint.SetPosition(stream, hintPosition);
}
/// <summary>
/// Sets the position for a hint and target for given bone positions.
/// </summary>
/// <param name="rootPosition">The position of the root bone.</param>
/// <param name="midPosition">The position of the mid bone.</param>
/// <param name="tipPosition">The position of the tip bone.</param>
/// <param name="tipRotation">The rotation of the tip bone.</param>
/// <param name="targetPosition">The position of the target.</param>
/// <param name="targetRotation">The rotation of the target.</param>
/// <param name="hintPosition">The position of the hint.</param>
/// <param name="isHintValid">Whether the hint position should be set.</param>
/// <param name="posWeight">The weight for which target position has an effect on IK calculations. This is a value in between 0 and 1.</param>
/// <param name="rotWeight">The weight for which target rotation has an effect on IK calculations. This is a value in between 0 and 1.</param>
/// <param name="hintWeight">The weight for which hint transform has an effect on IK calculations. This is a value in between 0 and 1.</param>
/// <param name="targetOffset">The offset applied to the target transform.</param>
public static void InverseSolveTwoBoneIK(
Vector3 rootPosition,
Vector3 midPosition,
Vector3 tipPosition, Quaternion tipRotation,
ref Vector3 targetPosition, ref Quaternion targetRotation,
ref Vector3 hintPosition, bool isHintValid,
float posWeight,
float rotWeight,
float hintWeight,
AffineTransform targetOffset
)
{
targetPosition = (posWeight > 0f) ? tipPosition + targetOffset.translation : targetPosition;
targetRotation = (rotWeight > 0f) ? tipRotation * targetOffset.rotation : targetRotation;
if (isHintValid)
{
var ac = tipPosition - rootPosition;
var ab = midPosition - rootPosition;
var bc = tipPosition - midPosition;
float abLen = ab.magnitude;
float bcLen = bc.magnitude;
var acSqrMag = Vector3.Dot(ac, ac);
var projectionPoint = rootPosition;
if (acSqrMag > k_SqrEpsilon)
projectionPoint += Vector3.Dot(ab / acSqrMag, ac) * ac;
var poleVectorDirection = midPosition - projectionPoint;
var scale = abLen + bcLen;
hintPosition = (hintWeight > 0f) ? projectionPoint + (poleVectorDirection.normalized * scale) : hintPosition;
}
}
static float TriangleAngle(float aLen, float aLen1, float aLen2)
{
float c = Mathf.Clamp((aLen1 * aLen1 + aLen2 * aLen2 - aLen * aLen) / (aLen1 * aLen2) / 2.0f, -1.0f, 1.0f);
return Mathf.Acos(c);
}
/// <summary>
/// Evaluates the FABRIK ChainIK algorithm.
/// </summary>
/// <param name="linkPositions">Uninitialized buffer of positions. linkPositions and linkLengths must have the same size.</param>
/// <param name="linkLengths">Array of distances in between positions. linkPositions and linkLenghts must have the same size.</param>
/// <param name="target">Target position.</param>
/// <param name="tolerance">The maximum distance the resulting position and initial target are allowed to have in between them.</param>
/// <param name="maxReach">The maximum distance the Transform chain can reach.</param>
/// <param name="maxIterations">The maximum number of iterations allowed for the ChainIK algorithm to converge to a solution.</param>
/// <returns>Returns true if ChainIK calculations were successful. False otherwise.</returns>
/// <remarks>
/// Implementation of unconstrained FABRIK solver : Forward and Backward Reaching Inverse Kinematic
/// Aristidou A, Lasenby J. FABRIK: a fast, iterative solver for the inverse kinematics problem. Graphical Models 2011; 73(5): 243260.
/// </remarks>
public static bool SolveFABRIK(
ref NativeArray<Vector3> linkPositions,
ref NativeArray<float> linkLengths,
Vector3 target,
float tolerance,
float maxReach,
int maxIterations
)
{
// If the target is unreachable
var rootToTargetDir = target - linkPositions[0];
if (rootToTargetDir.sqrMagnitude > Square(maxReach))
{
// Line up chain towards target
var dir = rootToTargetDir.normalized;
for (int i = 1; i < linkPositions.Length; ++i)
linkPositions[i] = linkPositions[i - 1] + dir * linkLengths[i - 1];
return true;
}
else
{
int tipIndex = linkPositions.Length - 1;
float sqrTolerance = Square(tolerance);
if (SqrDistance(linkPositions[tipIndex], target) > sqrTolerance)
{
var rootPos = linkPositions[0];
int iteration = 0;
do
{
// Forward reaching phase
// Set tip to target and propagate displacement to rest of chain
linkPositions[tipIndex] = target;
for (int i = tipIndex - 1; i > -1; --i)
linkPositions[i] = linkPositions[i + 1] + ((linkPositions[i] - linkPositions[i + 1]).normalized * linkLengths[i]);
// Backward reaching phase
// Set root back at it's original position and propagate displacement to rest of chain
linkPositions[0] = rootPos;
for (int i = 1; i < linkPositions.Length; ++i)
linkPositions[i] = linkPositions[i - 1] + ((linkPositions[i] - linkPositions[i - 1]).normalized * linkLengths[i - 1]);
}
while ((SqrDistance(linkPositions[tipIndex], target) > sqrTolerance) && (++iteration < maxIterations));
return true;
}
}
return false;
}
/// <summary>
/// Returns the square length between two vectors.
/// </summary>
/// <param name="lhs">Vector3 value.</param>
/// <param name="rhs">Vector3 value.</param>
/// <returns>Square length between lhs and rhs.</returns>
public static float SqrDistance(Vector3 lhs, Vector3 rhs)
{
return (rhs - lhs).sqrMagnitude;
}
/// <summary>
/// Returns the square value of a float.
/// </summary>
/// <param name="value">Float value.</param>
/// <returns>Squared value.</returns>
public static float Square(float value)
{
return value * value;
}
/// <summary>
/// Linearly interpolates between two vectors using a vector interpolant.
/// </summary>
/// <param name="a">Start Vector3 value.</param>
/// <param name="b">End Vector3 value.</param>
/// <param name="t">Interpolant Vector3 value.</param>
/// <returns>Interpolated value.</returns>
public static Vector3 Lerp(Vector3 a, Vector3 b, Vector3 t)
{
return Vector3.Scale(a, Vector3.one - t) + Vector3.Scale(b, t);
}
/// <summary>
/// Returns b if c is greater than zero, a otherwise.
/// </summary>
/// <param name="a">First float value.</param>
/// <param name="b">Second float value.</param>
/// <param name="c">Comparator float value.</param>
/// <returns>Selected float value.</returns>
public static float Select(float a, float b, float c)
{
return (c > 0f) ? b : a;
}
/// <summary>
/// Returns a componentwise selection between two vectors a and b based on a vector selection mask c.
/// Per component, the component from b is selected when c is greater than zero, otherwise the component from a is selected.
/// </summary>
/// <param name="a">First Vector3 value.</param>
/// <param name="b">Second Vector3 value.</param>
/// <param name="c">Comparator Vector3 value.</param>
/// <returns>Selected Vector3 value.</returns>
public static Vector3 Select(Vector3 a, Vector3 b, Vector3 c)
{
return new Vector3(Select(a.x, b.x, c.x), Select(a.y, b.y, c.y), Select(a.z, b.z, c.z));
}
/// <summary>
/// Projects a vector onto a plane defined by a normal orthogonal to the plane.
/// </summary>
/// <param name="vector">The location of the vector above the plane.</param>
/// <param name="planeNormal">The direction from the vector towards the plane.</param>
/// <returns>The location of the vector on the plane.</returns>
public static Vector3 ProjectOnPlane(Vector3 vector, Vector3 planeNormal)
{
float sqrMag = Vector3.Dot(planeNormal, planeNormal);
var dot = Vector3.Dot(vector, planeNormal);
return new Vector3(vector.x - planeNormal.x * dot / sqrMag,
vector.y - planeNormal.y * dot / sqrMag,
vector.z - planeNormal.z * dot / sqrMag);
}
internal static float Sum(AnimationJobCache cache, CacheIndex index, int count)
{
if (count == 0)
return 0f;
float sum = 0f;
for (int i = 0; i < count; ++i)
sum += cache.GetRaw(index, i);
return sum;
}
/// <summary>
/// Calculates the sum of all float elements in the array.
/// </summary>
/// <param name="floatBuffer">An array of float elements.</param>
/// <returns>Sum of all float elements.</returns>
public static float Sum(NativeArray<float> floatBuffer)
{
if (floatBuffer.Length == 0)
return 0f;
float sum = 0f;
for (int i = 0; i< floatBuffer.Length; ++i)
{
sum += floatBuffer[i];
}
return sum;
}
/// <summary>
/// Copies translation, rotation and scale values from specified Transform handle to stream.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
/// <param name="handle">The transform handle to copy.</param>
public static void PassThrough(AnimationStream stream, ReadWriteTransformHandle handle)
{
handle.GetLocalTRS(stream, out Vector3 position, out Quaternion rotation, out Vector3 scale);
handle.SetLocalTRS(stream, position, rotation, scale);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2c57b76759571b24baf139b32a086d87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,203 @@
using System.Collections.Generic;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The BoneRenderer component is responsible for displaying pickable bones in the Scene View.
/// This component does nothing during runtime.
/// </summary>
[ExecuteInEditMode]
[AddComponentMenu("Animation Rigging/Setup/Bone Renderer")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/RiggingWorkflow.html#bone-renderer-component")]
public class BoneRenderer : MonoBehaviour
{
/// <summary>
/// Shape used by individual bones.
/// </summary>
public enum BoneShape
{
/// <summary>Bones are rendered with single lines.</summary>
Line,
/// <summary>Bones are rendered with pyramid shapes.</summary>
Pyramid,
/// <summary>Bones are rendered with box shapes.</summary>
Box
};
/// <summary>Shape of the bones.</summary>
public BoneShape boneShape = BoneShape.Pyramid;
/// <summary>Toggles whether to render bone shapes or not.</summary>
public bool drawBones = true;
/// <summary>Toggles whether to draw tripods on bones or not.</summary>
public bool drawTripods = false;
/// <summary>Size of the bones.</summary>
[Range(0.01f, 5.0f)] public float boneSize = 1.0f;
/// <summary>Size of the tripod axis.</summary>
[Range(0.01f, 5.0f)] public float tripodSize = 1.0f;
/// <summary>Color of the bones.</summary>
public Color boneColor = new Color(0f, 0f, 1f, 0.5f);
[SerializeField] private Transform[] m_Transforms;
/// <summary>Transform references in the BoneRenderer hierarchy that are used to build bones.</summary>
public Transform[] transforms
{
get { return m_Transforms; }
#if UNITY_EDITOR
set
{
m_Transforms = value;
ExtractBones();
}
#endif
}
#if UNITY_EDITOR
/// <summary>
/// Bone described by two Transform references.
/// </summary>
public struct TransformPair
{
public Transform first;
public Transform second;
};
private TransformPair[] m_Bones;
private Transform[] m_Tips;
/// <summary>Retrieves the bones isolated from the Transform references.</summary>
/// <seealso cref="BoneRenderer.transforms"/>
public TransformPair[] bones
{
get => m_Bones;
}
/// <summary>Retrieves the tip bones isolated from the Transform references.</summary>
/// <seealso cref="BoneRenderer.transforms"/>
public Transform[] tips
{
get => m_Tips;
}
/// <summary>
/// Delegate function that covers a BoneRenderer calling OnEnable.
/// </summary>
/// <param name="boneRenderer">The BoneRenderer component</param>
public delegate void OnAddBoneRendererCallback(BoneRenderer boneRenderer);
/// <summary>
/// Delegate function that covers a BoneRenderer calling OnDisable.
/// </summary>
/// <param name="boneRenderer">The BoneRenderer component</param>
public delegate void OnRemoveBoneRendererCallback(BoneRenderer boneRenderer);
/// <summary>
/// Notification callback that is sent whenever a BoneRenderer calls OnEnable.
/// </summary>
public static OnAddBoneRendererCallback onAddBoneRenderer;
/// <summary>
/// Notification callback that is sent whenever a BoneRenderer calls OnDisable.
/// </summary>
public static OnRemoveBoneRendererCallback onRemoveBoneRenderer;
void OnEnable()
{
ExtractBones();
onAddBoneRenderer?.Invoke(this);
}
void OnDisable()
{
onRemoveBoneRenderer?.Invoke(this);
}
/// <summary>
/// Invalidate and Rebuild bones and tip bones from Transform references.
/// </summary>
public void Invalidate()
{
ExtractBones();
}
/// <summary>
/// Resets the BoneRenderer to default values.
/// </summary>
public void Reset()
{
ClearBones();
}
/// <summary>
/// Clears bones and tip bones.
/// </summary>
public void ClearBones()
{
m_Bones = null;
m_Tips = null;
}
/// <summary>
/// Builds bones and tip bones from Transform references.
/// </summary>
public void ExtractBones()
{
if (m_Transforms == null || m_Transforms.Length == 0)
{
ClearBones();
return;
}
var transformsHashSet = new HashSet<Transform>(m_Transforms);
var bonesList = new List<TransformPair>(m_Transforms.Length);
var tipsList = new List<Transform>(m_Transforms.Length);
for (int i = 0; i < m_Transforms.Length; ++i)
{
bool hasValidChildren = false;
var transform = m_Transforms[i];
if (transform == null)
continue;
if (UnityEditor.SceneVisibilityManager.instance.IsHidden(transform.gameObject, false))
continue;
var mask = UnityEditor.Tools.visibleLayers;
if ((mask & (1 << transform.gameObject.layer)) == 0)
continue;
if (transform.childCount > 0)
{
for (var k = 0; k < transform.childCount; ++k)
{
var childTransform = transform.GetChild(k);
if (transformsHashSet.Contains(childTransform))
{
bonesList.Add(new TransformPair() {first = transform, second = childTransform});
hasValidChildren = true;
}
}
}
if (!hasValidChildren)
{
tipsList.Add(transform);
}
}
m_Bones = bonesList.ToArray();
m_Tips = tipsList.ToArray();
}
#endif // UNITY_EDITOR
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b2d8418b0b9634b1892b0268dd9c2743
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: ca41524ec86f0d84ab5675c9622cc1a2, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// Utility functions for constraints.
/// </summary>
public static class ConstraintsUtils
{
/// <summary>
/// Creates a list of Transforms all parented to one another in between two GameObjects.
/// </summary>
/// <param name="root">The root Transform.</param>
/// <param name="tip">The tip Transform.</param>
/// <returns></returns>
public static Transform[] ExtractChain(Transform root, Transform tip)
{
if (!tip.IsChildOf(root))
return new Transform[0]{};
var chain = new List<Transform>();
Transform tmp = tip;
while (tmp != root)
{
chain.Add(tmp);
tmp = tmp.parent;
}
chain.Add(root);
chain.Reverse();
return chain.ToArray();
}
/// <summary>
/// Calculates the distances in between every Transforms in the specified Transform chain.
/// </summary>
/// <param name="chain">The Transform chain.</param>
/// <returns>An array of distances.</returns>
public static float[] ExtractLengths(Transform[] chain)
{
float[] lengths = new float[chain.Length];
lengths[0] = 0f;
// Evaluate lengths as distance between each transform in the chain.
for (int i = 1; i < chain.Length; ++i)
{
lengths[i] = chain[i].localPosition.magnitude;
}
return lengths;
}
/// <summary>
/// Calculates the interpolant values for each Transform using distance as a measure
/// such that first Transform is at 0 and last Transform is at 1.
/// </summary>
/// <param name="chain">The Transform chain.</param>
/// <returns>An array of interpolants.</returns>
public static float[] ExtractSteps(Transform[] chain)
{
float[] lengths = ExtractLengths(chain);
float totalLength = 0f;
Array.ForEach(lengths, (length) => totalLength += length);
float[] steps = new float[lengths.Length];
// Evaluate weights and steps based on curve.
float cumulativeLength = 0.0f;
for (int i = 0; i < lengths.Length; ++i)
{
cumulativeLength += lengths[i];
float t = cumulativeLength / totalLength;
steps[i] = t;
}
return steps;
}
/// <summary>
/// Prepends RigConstraint data property to specified property name.
/// </summary>
/// <param name="property">Property name.</param>
/// <returns>Return a complete property name.</returns>
public static string ConstructConstraintDataPropertyName(string property)
{
return "m_Data." + property;
}
/// <summary>
/// Builds a unique property name for a custom property.
/// </summary>
/// <param name="component">Associated component.</param>
/// <param name="property">Property name.</param>
/// <returns>Returns a custom property name.</returns>
public static string ConstructCustomPropertyName(Component component, string property)
{
return component.transform.GetInstanceID() + "/" + component.GetType() + "/" + property;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ff1d1a6b9dacf476fb3597334c297c7b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,77 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// Supplementary functions for Quaternion.
/// </summary>
public static class QuaternionExt
{
const float k_FloatMin = 1e-10f;
/// <summary>Zero quaternion. All quaternion channels are set to zero.</summary>
public static readonly Quaternion zero = new Quaternion(0f, 0f, 0f, 0f);
/// <summary>
/// Calculates a Quaternion rotation of one vector to another.
/// </summary>
/// <param name="from">Starting vector.</param>
/// <param name="to">Destination vector.</param>
/// <returns>Quaternion rotation.</returns>
public static Quaternion FromToRotation(Vector3 from, Vector3 to)
{
float theta = Vector3.Dot(from.normalized, to.normalized);
if (theta >= 1f)
return Quaternion.identity;
if (theta <= -1f)
{
Vector3 axis = Vector3.Cross(from, Vector3.right);
if (axis.sqrMagnitude == 0f)
axis = Vector3.Cross(from, Vector3.up);
return Quaternion.AngleAxis(180f, axis);
}
return Quaternion.AngleAxis(Mathf.Acos(theta) * Mathf.Rad2Deg, Vector3.Cross(from, to).normalized);
}
/// <summary>
/// Adds two quaternion.
/// </summary>
/// <param name="rhs">Quaternion value.</param>
/// <param name="lhs">Quaternion value.</param>
/// <returns>Added Quaternion.</returns>
public static Quaternion Add(Quaternion rhs, Quaternion lhs)
{
float sign = Mathf.Sign(Quaternion.Dot(rhs, lhs));
return new Quaternion(rhs.x + sign * lhs.x, rhs.y + sign * lhs.y, rhs.z + sign * lhs.z, rhs.w + sign * lhs.w);
}
/// <summary>
/// Multiplies all Quaternion channels by a scale value.
/// </summary>
/// <param name="q">Quaternion value.</param>
/// <param name="scale">Scale value.</param>
/// <returns>Scaled Quaternion.</returns>
public static Quaternion Scale(Quaternion q, float scale)
{
return new Quaternion(q.x * scale, q.y * scale, q.z * scale, q.w * scale);
}
/// <summary>
/// Normalizes a Quaternion. Returns identity if normalized Quaternion is not finite.
/// </summary>
/// <param name="q">Quaternion value.</param>
/// <returns>Normalized Quaternion.</returns>
public static Quaternion NormalizeSafe(Quaternion q)
{
float dot = Quaternion.Dot(q, q);
if (dot > k_FloatMin)
{
float rsqrt = 1.0f / Mathf.Sqrt(dot);
return new Quaternion(q.x * rsqrt, q.y * rsqrt, q.z * rsqrt, q.w * rsqrt);
}
return Quaternion.identity;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b62601624da18e54fb7fbc031f4ac8ae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,36 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// Three-dimensional boolean vector.
/// </summary>
[System.Serializable]
public struct Vector3Bool
{
/// <summary>X component of the vector.</summary>
public bool x;
/// <summary>Y component of the vector.</summary>
public bool y;
/// <summary>Z component of the vector.</summary>
public bool z;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="val">Boolean value for x, y and z.</param>
public Vector3Bool(bool val)
{
x = y = z = val;
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="x">Boolean value for x.</param>
/// <param name="y">Boolean value for y.</param>
/// <param name="z">Boolean value for z.</param>
public Vector3Bool(bool x, bool y, bool z)
{
this.x = x; this.y = y; this.z = z;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 545e69336e8e62e47817399d2c47b673
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: