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,8 @@
fileFormatVersion: 2
guid: 2409134bc1887e14bb5735db9784b1cb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,226 @@
using System.Collections.Generic;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// CacheIndex is used in AnimationJobCache to recover the index to the cached data.
/// </summary>
public struct CacheIndex
{
internal int idx;
}
/// <summary>
/// AnimationJobCache can be used in animation jobs to store values that
/// can be updated through the AnimationJobCache during the Update loop without
/// rebuilding the job.
/// </summary>
public struct AnimationJobCache : System.IDisposable
{
NativeArray<float> m_Data;
internal AnimationJobCache(float[] data)
{
m_Data = new NativeArray<float>(data, Allocator.Persistent);
}
/// <summary>
/// Dispose of the AnimationJobCache memory.
/// </summary>
public void Dispose()
{
m_Data.Dispose();
}
/// <summary>
/// Gets raw float data at specified index.
/// </summary>
/// <param name="index">CacheIndex value.</param>
/// <param name="offset">Offset to the CacheIndex.</param>
/// <returns>The raw float data.</returns>
public float GetRaw(CacheIndex index, int offset = 0)
{
return m_Data[index.idx + offset];
}
/// <summary>
/// Sets raw float data at specified index.
/// </summary>
/// <param name="val">Raw float data.</param>
/// <param name="index">CacheIndex value.</param>
/// <param name="offset">Offset to the CacheIndex.</param>
public void SetRaw(float val, CacheIndex index, int offset = 0)
{
m_Data[index.idx + offset] = val;
}
/// <summary>
/// Gets value at specified index.
/// </summary>
/// <param name="index">CacheIndex value.</param>
/// <param name="offset">Offset to the CacheIndex.</param>
/// <typeparam name="T">The value type.</typeparam>
/// <returns></returns>
unsafe public T Get<T>(CacheIndex index, int offset = 0) where T : unmanaged
{
int size = UnsafeUtility.SizeOf<T>();
int stride = size / UnsafeUtility.SizeOf<float>();
T val = default(T);
UnsafeUtility.MemCpy(&val, (float*)m_Data.GetUnsafeReadOnlyPtr() + index.idx + offset * stride, size);
return val;
}
/// <summary>
/// Sets value at specified index.
/// </summary>
/// <param name="val">Value.</param>
/// <param name="index">CacheIndex value.</param>
/// <param name="offset">Offset to the CacheIndex.</param>
/// <typeparam name="T"></typeparam>
unsafe public void Set<T>(T val, CacheIndex index, int offset = 0) where T : unmanaged
{
int size = UnsafeUtility.SizeOf<T>();
int stride = size / UnsafeUtility.SizeOf<float>();
UnsafeUtility.MemCpy((float*)m_Data.GetUnsafePtr() + index.idx + offset * stride, &val, size);
}
/// <summary>
/// Sets an array of values at specified index.
/// </summary>
/// <param name="v">Array of values.</param>
/// <param name="index">CacheIndex value.</param>
/// <param name="offset">Offset to the CacheIndex.</param>
/// <typeparam name="T"></typeparam>
unsafe public void SetArray<T>(T[] v, CacheIndex index, int offset = 0) where T : unmanaged
{
int size = UnsafeUtility.SizeOf<T>();
int stride = size / UnsafeUtility.SizeOf<float>();
fixed (void* ptr = v)
{
UnsafeUtility.MemCpy((float*)m_Data.GetUnsafePtr() + index.idx + offset * stride, ptr, size * v.Length);
}
}
}
/// <summary>
/// AnimationJobCacheBuilder can be used to create a new AnimationJobCache object.
/// </summary>
public class AnimationJobCacheBuilder
{
List<float> m_Data;
/// <summary>
/// Constructor.
/// </summary>
public AnimationJobCacheBuilder()
{
m_Data = new List<float>();
}
/// <summary>
/// Adds a float value to the AnimationJobCache.
/// </summary>
/// <param name="v">Float value.</param>
/// <returns>CacheIndex that refers to the new value.</returns>
public CacheIndex Add(float v)
{
m_Data.Add(v);
return new CacheIndex { idx = m_Data.Count - 1 };
}
/// <summary>
/// Adds a Vector2 value to the AnimationJobCache.
/// </summary>
/// <param name="v">Vector2 value.</param>
/// <returns>CacheIndex that refers to the new value.</returns>
public CacheIndex Add(Vector2 v)
{
m_Data.Add(v.x);
m_Data.Add(v.y);
return new CacheIndex { idx = m_Data.Count - 2 };
}
/// <summary>
/// Adds a Vector3 value to the AnimationJobCache.
/// </summary>
/// <param name="v">Vector3 value.</param>
/// <returns>CacheIndex that refers to the new value.</returns>
public CacheIndex Add(Vector3 v)
{
m_Data.Add(v.x);
m_Data.Add(v.y);
m_Data.Add(v.z);
return new CacheIndex { idx = m_Data.Count - 3 };
}
/// <summary>
/// Adds a Vector4 value to the AnimationJobCache.
/// </summary>
/// <param name="v">Vector4 value.</param>
/// <returns>CacheIndex that refers to the new value.</returns>
public CacheIndex Add(Vector4 v)
{
m_Data.Add(v.x);
m_Data.Add(v.y);
m_Data.Add(v.z);
m_Data.Add(v.w);
return new CacheIndex { idx = m_Data.Count - 4 };
}
/// <summary>
/// Adds a Quaternion value to the AnimationJobCache.
/// </summary>
/// <param name="v">Quaternion value.</param>
/// <returns>CacheIndex that refers to the new value.</returns>
public CacheIndex Add(Quaternion v)
{
return Add(new Vector4(v.x, v.y, v.z, v.w));
}
/// <summary>
/// Adds a AffineTransform value to the AnimationJobCache.
/// </summary>
/// <param name="tx">AffineTransform value.</param>
/// <returns>CacheIndex that refers to the new value.</returns>
public CacheIndex Add(AffineTransform tx)
{
Add(tx.translation);
Add(tx.rotation);
return new CacheIndex { idx = m_Data.Count - 7 };
}
/// <summary>
/// Allocates uninitialized chunk of specified size in the AnimationJobCacheBuilder.
/// </summary>
/// <param name="size">Size of chunk to allocate.</param>
/// <returns>CacheIndex that refers to the allocated chunk.</returns>
public CacheIndex AllocateChunk(int size)
{
m_Data.AddRange(new float[size]);
return new CacheIndex { idx = m_Data.Count - size };
}
/// <summary>
/// Sets value in AnimationJobCacheBuilder at specified index.
/// </summary>
/// <param name="index">CacheIndex value.</param>
/// <param name="offset">Offset to the CacheIndex.</param>
/// <param name="value">float data.</param>
public void SetValue(CacheIndex index, int offset, float value)
{
if (index.idx + offset < m_Data.Count)
m_Data[index.idx + offset] = value;
}
/// <summary>
/// Creates a new AnimationJobCache.
/// </summary>
/// <returns>AnimationJobCache object with newly set values.</returns>
public AnimationJobCache Build() => new AnimationJobCache(m_Data.ToArray());
}
}

View File

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

View File

@@ -0,0 +1,156 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The Blend constraint job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct BlendConstraintJob : IWeightedAnimationJob
{
private const int k_BlendTranslationMask = 1 << 0;
private const int k_BlendRotationMask = 1 << 1;
/// <summary>The Transform handle for the constrained object Transform.</summary>
public ReadWriteTransformHandle driven;
/// <summary>The Transform handle for sourceA Transform.</summary>
public ReadOnlyTransformHandle sourceA;
/// <summary>The Transform handle for sourceB Transform.</summary>
public ReadOnlyTransformHandle sourceB;
/// <summary>TR offset to apply to sourceA if maintainOffset is enabled.</summary>
public AffineTransform sourceAOffset;
/// <summary>TR offset to apply to sourceB if maintainOffset is enabled.</summary>
public AffineTransform sourceBOffset;
/// <summary>Toggles whether to blend position in the job.</summary>
public BoolProperty blendPosition;
/// <summary>Toggles whether to blend rotation in the job.</summary>
public BoolProperty blendRotation;
/// <summary>
/// Specifies the weight with which to blend position.
/// A weight of zero will result in the position of sourceA, while a weight of one will result in the position of sourceB.
/// </summary>
public FloatProperty positionWeight;
/// <summary>
/// Specifies the weight with which to blend rotation.
/// A weight of zero will result in the rotation of sourceA, while a weight of one will result in the rotation of sourceB.
/// </summary>
public FloatProperty rotationWeight;
/// <inheritdoc />
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
if (blendPosition.Get(stream))
{
Vector3 posBlend = Vector3.Lerp(
sourceA.GetPosition(stream) + sourceAOffset.translation,
sourceB.GetPosition(stream) + sourceBOffset.translation,
positionWeight.Get(stream)
);
driven.SetPosition(stream, Vector3.Lerp(driven.GetPosition(stream), posBlend, w));
}
else
driven.SetLocalPosition(stream, driven.GetLocalPosition(stream));
if (blendRotation.Get(stream))
{
Quaternion rotBlend = Quaternion.Lerp(
sourceA.GetRotation(stream) * sourceAOffset.rotation,
sourceB.GetRotation(stream) * sourceBOffset.rotation,
rotationWeight.Get(stream)
);
driven.SetRotation(stream, Quaternion.Lerp(driven.GetRotation(stream), rotBlend, w));
}
else
driven.SetLocalRotation(stream, driven.GetLocalRotation(stream));
}
else
AnimationRuntimeUtils.PassThrough(stream, driven);
}
}
/// <summary>
/// This interface defines the data mapping for the Blend constraint.
/// </summary>
public interface IBlendConstraintData
{
/// <summary>The Transform affected by the two source Transforms.</summary>
Transform constrainedObject { get; }
/// <summary>First Transform in blend.</summary>
Transform sourceObjectA { get; }
/// <summary>Second Transform in blend.</summary>
Transform sourceObjectB { get; }
/// <summary>This is used to maintain the current position offset from the constrained GameObject to the source GameObjects.</summary>
bool maintainPositionOffsets { get; }
/// <summary>This is used to maintain the current rotation offset from the constrained GameObject to the source GameObjects.</summary>
bool maintainRotationOffsets { get; }
/// <summary>The path to the blend position property in the constraint component.</summary>
string blendPositionBoolProperty { get; }
/// <summary>The path to the blend rotation property in the constraint component.</summary>
string blendRotationBoolProperty { get; }
/// <summary>The path to the position weight property in the constraint component.</summary>
string positionWeightFloatProperty { get; }
/// <summary>The path to the rotation weight property in the constraint component.</summary>
string rotationWeightFloatProperty { get; }
}
/// <summary>
/// The Blend constraint job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class BlendConstraintJobBinder<T> : AnimationJobBinder<BlendConstraintJob, T>
where T : struct, IAnimationJobData, IBlendConstraintData
{
/// <inheritdoc />
public override BlendConstraintJob Create(Animator animator, ref T data, Component component)
{
var job = new BlendConstraintJob();
job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject);
job.sourceA = ReadOnlyTransformHandle.Bind(animator, data.sourceObjectA);
job.sourceB = ReadOnlyTransformHandle.Bind(animator, data.sourceObjectB);
job.sourceAOffset = job.sourceBOffset = AffineTransform.identity;
if (data.maintainPositionOffsets)
{
var drivenPos = data.constrainedObject.position;
job.sourceAOffset.translation = drivenPos - data.sourceObjectA.position;
job.sourceBOffset.translation = drivenPos - data.sourceObjectB.position;
}
if (data.maintainRotationOffsets)
{
var drivenRot = data.constrainedObject.rotation;
job.sourceAOffset.rotation = Quaternion.Inverse(data.sourceObjectA.rotation) * drivenRot;
job.sourceBOffset.rotation = Quaternion.Inverse(data.sourceObjectB.rotation) * drivenRot;
}
job.blendPosition = BoolProperty.Bind(animator, component, data.blendPositionBoolProperty);
job.blendRotation = BoolProperty.Bind(animator, component, data.blendRotationBoolProperty);
job.positionWeight = FloatProperty.Bind(animator, component, data.positionWeightFloatProperty);
job.rotationWeight = FloatProperty.Bind(animator, component, data.rotationWeightFloatProperty);
return job;
}
/// <inheritdoc />
public override void Destroy(BlendConstraintJob job)
{
}
}
}

View File

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

View File

@@ -0,0 +1,188 @@
using Unity.Collections;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The ChainIK constraint job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct ChainIKConstraintJob : IWeightedAnimationJob
{
/// <summary>An array of Transform handles that represents the Transform chain.</summary>
public NativeArray<ReadWriteTransformHandle> chain;
/// <summary>The Transform handle for the target Transform.</summary>
public ReadOnlyTransformHandle target;
/// <summary>The offset applied to the target transform if maintainTargetPositionOffset or maintainTargetRotationOffset is enabled.</summary>
public AffineTransform targetOffset;
/// <summary>An array of length in between Transforms in the chain.</summary>
public NativeArray<float> linkLengths;
/// <summary>An array of positions for Transforms in the chain.</summary>
public NativeArray<Vector3> linkPositions;
/// <summary>The weight for which ChainIK target has an effect on chain (up to tip Transform). This is a value in between 0 and 1.</summary>
public FloatProperty chainRotationWeight;
/// <summary>The weight for which ChainIK target has and effect on tip Transform. This is a value in between 0 and 1.</summary>
public FloatProperty tipRotationWeight;
/// <summary>CacheIndex to ChainIK tolerance value.</summary>
/// <seealso cref="AnimationJobCache"/>
public CacheIndex toleranceIdx;
/// <summary>CacheIndex to ChainIK maxIterations value.</summary>
/// <seealso cref="AnimationJobCache"/>
public CacheIndex maxIterationsIdx;
/// <summary>Cache for static properties in the job.</summary>
public AnimationJobCache cache;
/// <summary>The maximum distance the Transform chain can reach.</summary>
public float maxReach;
/// <inheritdoc />
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
for (int i = 0; i < chain.Length; ++i)
{
var handle = chain[i];
linkPositions[i] = handle.GetPosition(stream);
chain[i] = handle;
}
int tipIndex = chain.Length - 1;
if (AnimationRuntimeUtils.SolveFABRIK(ref linkPositions, ref linkLengths, target.GetPosition(stream) + targetOffset.translation,
cache.GetRaw(toleranceIdx), maxReach, (int)cache.GetRaw(maxIterationsIdx)))
{
var chainRWeight = chainRotationWeight.Get(stream) * w;
for (int i = 0; i < tipIndex; ++i)
{
var prevDir = chain[i + 1].GetPosition(stream) - chain[i].GetPosition(stream);
var newDir = linkPositions[i + 1] - linkPositions[i];
var rot = chain[i].GetRotation(stream);
chain[i].SetRotation(stream, Quaternion.Lerp(rot, QuaternionExt.FromToRotation(prevDir, newDir) * rot, chainRWeight));
}
}
chain[tipIndex].SetRotation(
stream,
Quaternion.Lerp(
chain[tipIndex].GetRotation(stream),
target.GetRotation(stream) * targetOffset.rotation,
tipRotationWeight.Get(stream) * w
)
);
}
else
{
for (int i = 0; i < chain.Length; ++i)
AnimationRuntimeUtils.PassThrough(stream, chain[i]);
}
}
}
/// <summary>
/// This interface defines the data mapping for the ChainIK constraint.
/// </summary>
public interface IChainIKConstraintData
{
/// <summary>The root Transform of the ChainIK hierarchy.</summary>
Transform root { get; }
/// <summary>The tip Transform of the ChainIK hierarchy. The tip needs to be a descendant/child of the root Transform.</summary>
Transform tip { get; }
/// <summary>The ChainIK target Transform.</summary>
Transform target { get; }
/// <summary>The maximum number of iterations allowed for the ChainIK algorithm to converge to a solution.</summary>
int maxIterations { get; }
/// <summary>
/// The allowed distance between the tip and target Transform positions.
/// When the distance is smaller than the tolerance, the algorithm has converged on a solution and will stop.
/// </summary>
float tolerance { get; }
/// <summary>This is used to maintain the current position offset from the tip Transform to target Transform.</summary>
bool maintainTargetPositionOffset { get; }
/// <summary>This is used to maintain the current rotation offset from the tip Transform to target Transform.</summary>
bool maintainTargetRotationOffset { get; }
/// <summary>The path to the chain rotation weight property in the constraint component.</summary>
string chainRotationWeightFloatProperty { get; }
/// <summary>The path to the tip rotation weight property in the constraint component.</summary>
string tipRotationWeightFloatProperty { get; }
}
/// <summary>
/// The ChainIK constraint job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class ChainIKConstraintJobBinder<T> : AnimationJobBinder<ChainIKConstraintJob, T>
where T : struct, IAnimationJobData, IChainIKConstraintData
{
/// <inheritdoc />
public override ChainIKConstraintJob Create(Animator animator, ref T data, Component component)
{
Transform[] chain = ConstraintsUtils.ExtractChain(data.root, data.tip);
var job = new ChainIKConstraintJob();
job.chain = new NativeArray<ReadWriteTransformHandle>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.linkLengths = new NativeArray<float>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.linkPositions = new NativeArray<Vector3>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.maxReach = 0f;
int tipIndex = chain.Length - 1;
for (int i = 0; i < chain.Length; ++i)
{
job.chain[i] = ReadWriteTransformHandle.Bind(animator, chain[i]);
job.linkLengths[i] = (i != tipIndex) ? Vector3.Distance(chain[i].position, chain[i + 1].position) : 0f;
job.maxReach += job.linkLengths[i];
}
job.target = ReadOnlyTransformHandle.Bind(animator, data.target);
job.targetOffset = AffineTransform.identity;
if (data.maintainTargetPositionOffset)
job.targetOffset.translation = data.tip.position - data.target.position;
if (data.maintainTargetRotationOffset)
job.targetOffset.rotation = Quaternion.Inverse(data.target.rotation) * data.tip.rotation;
job.chainRotationWeight = FloatProperty.Bind(animator, component, data.chainRotationWeightFloatProperty);
job.tipRotationWeight = FloatProperty.Bind(animator, component, data.tipRotationWeightFloatProperty);
var cacheBuilder = new AnimationJobCacheBuilder();
job.maxIterationsIdx = cacheBuilder.Add(data.maxIterations);
job.toleranceIdx = cacheBuilder.Add(data.tolerance);
job.cache = cacheBuilder.Build();
return job;
}
/// <inheritdoc />
public override void Destroy(ChainIKConstraintJob job)
{
job.chain.Dispose();
job.linkLengths.Dispose();
job.linkPositions.Dispose();
job.cache.Dispose();
}
/// <inheritdoc />
public override void Update(ChainIKConstraintJob job, ref T data)
{
job.cache.SetRaw(data.maxIterations, job.maxIterationsIdx);
job.cache.SetRaw(data.tolerance, job.toleranceIdx);
}
}
}

View File

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

View File

@@ -0,0 +1,160 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The DampedTransform job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct DampedTransformJob : IWeightedAnimationJob
{
const float k_FixedDt = 0.01667f; // 60Hz simulation step
const float k_DampFactor = 40f;
/// <summary>The Transform handle for the constrained object Transform.</summary>
public ReadWriteTransformHandle driven;
/// <summary>The Transform handle for the source object Transform.</summary>
public ReadOnlyTransformHandle source;
/// <summary>Initial TR offset from source to constrained object.</summary>
public AffineTransform localBindTx;
/// <summary>Aim axis used to adjust constrained object rotation if maintainAim is enabled.</summary>
public Vector3 aimBindAxis;
/// <summary>Previous frame driven Transform TR components.</summary>
public AffineTransform prevDrivenTx;
/// <summary>
/// Defines how much of constrained object position follows source object position.
/// constrained position will closely follow source object when set to 0, and will
/// not move when set to 1.
/// </summary>
public FloatProperty dampPosition;
/// <summary>
/// Defines how much of constrained object rotation follows source object rotation.
/// constrained rotation will closely follow source object when set to 0, and will
/// not move when set to 1.
/// </summary>
public FloatProperty dampRotation;
/// <inheritdoc />
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
float streamDt = Mathf.Abs(stream.deltaTime);
driven.GetGlobalTR(stream, out Vector3 drivenPos, out Quaternion drivenRot);
if (w > 0f && streamDt > 0f)
{
source.GetGlobalTR(stream, out Vector3 sourcePos, out Quaternion sourceRot);
var sourceTx = new AffineTransform(sourcePos, sourceRot);
var targetTx = sourceTx * localBindTx;
targetTx.translation = Vector3.Lerp(drivenPos, targetTx.translation, w);
targetTx.rotation = Quaternion.Lerp(drivenRot, targetTx.rotation, w);
var dampPosW = AnimationRuntimeUtils.Square(1f - dampPosition.Get(stream));
var dampRotW = AnimationRuntimeUtils.Square(1f - dampRotation.Get(stream));
bool doAimAjustements = Vector3.Dot(aimBindAxis, aimBindAxis) > 0f;
while (streamDt > 0f)
{
float factoredDt = k_DampFactor * Mathf.Min(k_FixedDt, streamDt);
prevDrivenTx.translation +=
(targetTx.translation - prevDrivenTx.translation) * dampPosW * factoredDt;
prevDrivenTx.rotation *= Quaternion.Lerp(
Quaternion.identity,
Quaternion.Inverse(prevDrivenTx.rotation) * targetTx.rotation,
dampRotW * factoredDt
);
if (doAimAjustements)
{
var fromDir = prevDrivenTx.rotation * aimBindAxis;
var toDir = sourceTx.translation - prevDrivenTx.translation;
prevDrivenTx.rotation =
Quaternion.AngleAxis(Vector3.Angle(fromDir, toDir), Vector3.Cross(fromDir, toDir).normalized) * prevDrivenTx.rotation;
}
streamDt -= k_FixedDt;
}
driven.SetGlobalTR(stream, prevDrivenTx.translation, prevDrivenTx.rotation);
}
else
{
prevDrivenTx.Set(drivenPos, drivenRot);
AnimationRuntimeUtils.PassThrough(stream, driven);
}
}
}
/// <summary>
/// This interface defines the data mapping for DampedTransform.
/// </summary>
public interface IDampedTransformData
{
/// <summary>The Transform affected by the constraint Source Transform.</summary>
Transform constrainedObject { get; }
/// <summary>The source Transform.</summary>
Transform sourceObject { get; }
/// <summary>Toggles whether damping will enforces aim.</summary>
bool maintainAim { get; }
/// <summary>The path to the damp position weight property in the constraint component.</summary>
string dampPositionFloatProperty { get; }
/// <summary>The path to the damp rotation weight property in the constraint component.</summary>
string dampRotationFloatProperty { get; }
}
/// <summary>
/// The DampedTransform job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class DampedTransformJobBinder<T> : AnimationJobBinder<DampedTransformJob, T>
where T : struct, IAnimationJobData, IDampedTransformData
{
/// <inheritdoc />
public override DampedTransformJob Create(Animator animator, ref T data, Component component)
{
var job = new DampedTransformJob();
job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject);
job.source = ReadOnlyTransformHandle.Bind(animator, data.sourceObject);
var drivenTx = new AffineTransform(data.constrainedObject.position, data.constrainedObject.rotation);
var sourceTx = new AffineTransform(data.sourceObject.position, data.sourceObject.rotation);
job.localBindTx = sourceTx.InverseMul(drivenTx);
job.prevDrivenTx = drivenTx;
job.dampPosition = FloatProperty.Bind(animator, component, data.dampPositionFloatProperty);
job.dampRotation = FloatProperty.Bind(animator, component, data.dampRotationFloatProperty);
if (data.maintainAim && AnimationRuntimeUtils.SqrDistance(data.constrainedObject.position, data.sourceObject.position) > 0f)
job.aimBindAxis = Quaternion.Inverse(data.constrainedObject.rotation) * (sourceTx.translation - drivenTx.translation).normalized;
else
job.aimBindAxis = Vector3.zero;
return job;
}
/// <inheritdoc />
public override void Destroy(DampedTransformJob job)
{
}
}
}

View File

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

View File

@@ -0,0 +1,511 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// Interface for animatable property handles used to read and write
/// values in the AnimationStream.
/// </summary>
/// <typeparam name="T">The animatable value type</typeparam>
public interface IAnimatableProperty<T>
{
/// <summary>
/// Gets the property value from a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The property value.</returns>
T Get(AnimationStream stream);
/// <summary>
/// Sets the property value into a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="value">The new property value.</param>
void Set(AnimationStream stream, T value);
}
/// <summary>
/// Boolean property handle used to read and write values in the AnimationStream.
/// </summary>
public struct BoolProperty : IAnimatableProperty<bool>
{
/// <summary>The PropertyStreamHandle used in the AnimationStream.</summary>
public PropertyStreamHandle value;
/// <summary>
/// Creates a BoolProperty handle representing a property binding on a Component.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="component">The Component owning the parameter.</param>
/// <param name="name">The property name</param>
/// <returns>Returns a BoolProperty handle that represents the new binding.</returns>
public static BoolProperty Bind(Animator animator, Component component, string name)
{
return new BoolProperty()
{
value = animator.BindStreamProperty(component.transform, component.GetType(), name)
};
}
/// <summary>
/// Creates a BoolProperty handle for a custom property in the AnimationStream to pass extra data to downstream animation jobs in the graph.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="property">The name of the property.</param>
/// <returns>Returns a BoolProperty handle that represents the new binding.</returns>
public static BoolProperty BindCustom(Animator animator, string property)
{
return new BoolProperty
{
value = animator.BindCustomStreamProperty(property, CustomStreamPropertyType.Bool)
};
}
/// <summary>
/// Gets the property value from a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The boolean property value.</returns>
public bool Get(AnimationStream stream) => value.GetBool(stream);
/// <summary>
/// Sets the property value into a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="v">The new boolean property value.</param>
public void Set(AnimationStream stream, bool v) => value.SetBool(stream, v);
}
/// <summary>
/// Integer property handle used to read and write values in the AnimationStream.
/// </summary>
public struct IntProperty : IAnimatableProperty<int>
{
/// <summary>The PropertyStreamHandle used in the AnimationStream.</summary>
public PropertyStreamHandle value;
/// <summary>
/// Creates a IntProperty handle representing a property binding on a Component.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="component">The Component owning the parameter.</param>
/// <param name="name">The property name</param>
/// <returns>Returns a IntProperty handle that represents the new binding.</returns>
public static IntProperty Bind(Animator animator, Component component, string name)
{
return new IntProperty()
{
value = animator.BindStreamProperty(component.transform, component.GetType(), name)
};
}
/// <summary>
/// Creates a IntProperty handle for a custom property in the AnimationStream to pass extra data to downstream animation jobs in the graph.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="property">The name of the property.</param>
/// <returns>Returns a IntProperty handle that represents the new binding.</returns>
public static IntProperty BindCustom(Animator animator, string property)
{
return new IntProperty
{
value = animator.BindCustomStreamProperty(property, CustomStreamPropertyType.Int)
};
}
/// <summary>
/// Gets the property value from a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The integer property value.</returns>
public int Get(AnimationStream stream) => value.GetInt(stream);
/// <summary>
/// Sets the property value into a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="v">The new integer property value.</param>
public void Set(AnimationStream stream, int v) => value.SetInt(stream, v);
}
/// <summary>
/// Float property handle used to read and write values in the AnimationStream.
/// </summary>
public struct FloatProperty : IAnimatableProperty<float>
{
/// <summary>The PropertyStreamHandle used in the AnimationStream.</summary>
public PropertyStreamHandle value;
/// <summary>
/// Creates a FloatProperty handle representing a property binding on a Component.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="component">The Component owning the parameter.</param>
/// <param name="name">The property name</param>
/// <returns>Returns a FloatProperty handle that represents the new binding.</returns>
public static FloatProperty Bind(Animator animator, Component component, string name)
{
return new FloatProperty()
{
value = animator.BindStreamProperty(component.transform, component.GetType(), name)
};
}
/// <summary>
/// Creates a FloatProperty handle for a custom property in the AnimationStream to pass extra data to downstream animation jobs in the graph.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="property">The name of the property.</param>
/// <returns>Returns a FloatProperty handle that represents the new binding.</returns>
public static FloatProperty BindCustom(Animator animator, string property)
{
return new FloatProperty
{
value = animator.BindCustomStreamProperty(property, CustomStreamPropertyType.Float)
};
}
/// <summary>
/// Gets the property value from a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The float property value.</returns>
public float Get(AnimationStream stream) => value.GetFloat(stream);
/// <summary>
/// Sets the property value into a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="v">The new float property value.</param>
public void Set(AnimationStream stream, float v) => value.SetFloat(stream, v);
}
/// <summary>
/// Vector2 property handle used to read and write values in the AnimationStream.
/// </summary>
public struct Vector2Property : IAnimatableProperty<Vector2>
{
/// <summary>The PropertyStreamHandle used for the X component in the AnimationStream.</summary>
public PropertyStreamHandle x;
/// <summary>The PropertyStreamHandle used for the Y component in the AnimationStream.</summary>
public PropertyStreamHandle y;
/// <summary>
/// Creates a Vector2Property handle representing a property binding on a Component.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="component">The Component owning the parameter.</param>
/// <param name="name">The property name</param>
/// <returns>Returns a Vector2Property handle that represents the new binding.</returns>
public static Vector2Property Bind(Animator animator, Component component, string name)
{
var type = component.GetType();
return new Vector2Property
{
x = animator.BindStreamProperty(component.transform, type, name + ".x"),
y = animator.BindStreamProperty(component.transform, type, name + ".y")
};
}
/// <summary>
/// Creates a Vector2Property handle for a custom property in the AnimationStream to pass extra data to downstream animation jobs in the graph.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="name">The name of the property.</param>
/// <returns>Returns a Vector2Property handle that represents the new binding.</returns>
public static Vector2Property BindCustom(Animator animator, string name)
{
return new Vector2Property
{
x = animator.BindCustomStreamProperty(name + ".x", CustomStreamPropertyType.Float),
y = animator.BindCustomStreamProperty(name + ".y", CustomStreamPropertyType.Float)
};
}
/// <summary>
/// Gets the property value from a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The Vector2 property value.</returns>
public Vector2 Get(AnimationStream stream) =>
new Vector2(x.GetFloat(stream), y.GetFloat(stream));
/// <summary>
/// Sets the property value into a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="value">The new Vector2 property value.</param>
public void Set(AnimationStream stream, Vector2 value)
{
x.SetFloat(stream, value.x);
y.SetFloat(stream, value.y);
}
}
/// <summary>
/// Vector3 property handle used to read and write values in the AnimationStream.
/// </summary>
public struct Vector3Property : IAnimatableProperty<Vector3>
{
/// <summary>The PropertyStreamHandle used for the X component in the AnimationStream.</summary>
public PropertyStreamHandle x;
/// <summary>The PropertyStreamHandle used for the Y component in the AnimationStream.</summary>
public PropertyStreamHandle y;
/// <summary>The PropertyStreamHandle used for the Z component in the AnimationStream.</summary>
public PropertyStreamHandle z;
/// <summary>
/// Creates a Vector3Property handle representing a property binding on a Component.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="component">The Component owning the parameter.</param>
/// <param name="name">The property name</param>
/// <returns>Returns a Vector3Property handle that represents the new binding.</returns>
public static Vector3Property Bind(Animator animator, Component component, string name)
{
var type = component.GetType();
return new Vector3Property
{
x = animator.BindStreamProperty(component.transform, type, name + ".x"),
y = animator.BindStreamProperty(component.transform, type, name + ".y"),
z = animator.BindStreamProperty(component.transform, type, name + ".z")
};
}
/// <summary>
/// Creates a Vector3Property handle for a custom property in the AnimationStream to pass extra data to downstream animation jobs in the graph.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="name">The name of the property.</param>
/// <returns>Returns a Vector3Property handle that represents the new binding.</returns>
public static Vector3Property BindCustom(Animator animator, string name)
{
return new Vector3Property
{
x = animator.BindCustomStreamProperty(name + ".x", CustomStreamPropertyType.Float),
y = animator.BindCustomStreamProperty(name + ".y", CustomStreamPropertyType.Float),
z = animator.BindCustomStreamProperty(name + ".z", CustomStreamPropertyType.Float)
};
}
/// <summary>
/// Gets the property value from a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The Vector3 property value.</returns>
public Vector3 Get(AnimationStream stream) =>
new Vector3(x.GetFloat(stream), y.GetFloat(stream), z.GetFloat(stream));
/// <summary>
/// Sets the property value into a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="value">The new Vector3 property value.</param>
public void Set(AnimationStream stream, Vector3 value)
{
x.SetFloat(stream, value.x);
y.SetFloat(stream, value.y);
z.SetFloat(stream, value.z);
}
}
/// <summary>
/// Vector3Int property handle used to read and write values in the AnimationStream.
/// </summary>
public struct Vector3IntProperty : IAnimatableProperty<Vector3Int>
{
/// <summary>The PropertyStreamHandle used for the X component in the AnimationStream.</summary>
public PropertyStreamHandle x;
/// <summary>The PropertyStreamHandle used for the Y component in the AnimationStream.</summary>
public PropertyStreamHandle y;
/// <summary>The PropertyStreamHandle used for the Z component in the AnimationStream.</summary>
public PropertyStreamHandle z;
/// <summary>
/// Creates a Vector3IntProperty handle representing a property binding on a Component.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="component">The Component owning the parameter.</param>
/// <param name="name">The property name</param>
/// <returns>Returns a Vector3IntProperty handle that represents the new binding.</returns>
public static Vector3IntProperty Bind(Animator animator, Component component, string name)
{
var type = component.GetType();
return new Vector3IntProperty
{
x = animator.BindStreamProperty(component.transform, type, name + ".x"),
y = animator.BindStreamProperty(component.transform, type, name + ".y"),
z = animator.BindStreamProperty(component.transform, type, name + ".z")
};
}
/// <summary>
/// Creates a Vector3IntProperty handle for a custom property in the AnimationStream to pass extra data to downstream animation jobs in the graph.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="name">The name of the property.</param>
/// <returns>Returns a Vector3IntProperty handle that represents the new binding.</returns>
public static Vector3IntProperty BindCustom(Animator animator, string name)
{
return new Vector3IntProperty
{
x = animator.BindCustomStreamProperty(name + ".x", CustomStreamPropertyType.Int),
y = animator.BindCustomStreamProperty(name + ".y", CustomStreamPropertyType.Int),
z = animator.BindCustomStreamProperty(name + ".z", CustomStreamPropertyType.Int)
};
}
/// <summary>
/// Gets the property value from a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The Vector3Int property value.</returns>
public Vector3Int Get(AnimationStream stream) =>
new Vector3Int(x.GetInt(stream), y.GetInt(stream), z.GetInt(stream));
/// <summary>
/// Sets the property value into a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="value">The new Vector3Int property value.</param>
public void Set(AnimationStream stream, Vector3Int value)
{
x.SetInt(stream, value.x);
y.SetInt(stream, value.y);
z.SetInt(stream, value.z);
}
}
/// <summary>
/// Vector3Bool property handle used to read and write values in the AnimationStream.
/// </summary>
public struct Vector3BoolProperty : IAnimatableProperty<Vector3Bool>
{
/// <summary>The PropertyStreamHandle used for the X component in the AnimationStream.</summary>
public PropertyStreamHandle x;
/// <summary>The PropertyStreamHandle used for the Y component in the AnimationStream.</summary>
public PropertyStreamHandle y;
/// <summary>The PropertyStreamHandle used for the Z component in the AnimationStream.</summary>
public PropertyStreamHandle z;
/// <summary>
/// Creates a Vector3BoolProperty handle representing a property binding on a Component.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="component">The Component owning the parameter.</param>
/// <param name="name">The property name</param>
/// <returns>Returns a Vector3BoolProperty handle that represents the new binding.</returns>
public static Vector3BoolProperty Bind(Animator animator, Component component, string name)
{
var type = component.GetType();
return new Vector3BoolProperty
{
x = animator.BindStreamProperty(component.transform, type, name + ".x"),
y = animator.BindStreamProperty(component.transform, type, name + ".y"),
z = animator.BindStreamProperty(component.transform, type, name + ".z")
};
}
/// <summary>
/// Creates a Vector3BoolProperty handle for a custom property in the AnimationStream to pass extra data to downstream animation jobs in the graph.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="name">The name of the property.</param>
/// <returns>Returns a Vector3BoolProperty handle that represents the new binding.</returns>
public static Vector3BoolProperty BindCustom(Animator animator, string name)
{
return new Vector3BoolProperty
{
x = animator.BindCustomStreamProperty(name + ".x", CustomStreamPropertyType.Bool),
y = animator.BindCustomStreamProperty(name + ".y", CustomStreamPropertyType.Bool),
z = animator.BindCustomStreamProperty(name + ".z", CustomStreamPropertyType.Bool)
};
}
/// <summary>
/// Gets the property value from a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The Vector3Bool property value.</returns>
public Vector3Bool Get(AnimationStream stream) =>
new Vector3Bool(x.GetBool(stream), y.GetBool(stream), z.GetBool(stream));
/// <summary>
/// Sets the property value into a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="value">The new Vector3Bool property value.</param>
public void Set(AnimationStream stream, Vector3Bool value)
{
x.SetBool(stream, value.x);
y.SetBool(stream, value.y);
z.SetBool(stream, value.z);
}
}
/// <summary>
/// Vector4 property handle used to read and write values in the AnimationStream.
/// </summary>
public struct Vector4Property : IAnimatableProperty<Vector4>
{
/// <summary>The PropertyStreamHandle used for the X component in the AnimationStream.</summary>
public PropertyStreamHandle x;
/// <summary>The PropertyStreamHandle used for the Y component in the AnimationStream.</summary>
public PropertyStreamHandle y;
/// <summary>The PropertyStreamHandle used for the Z component in the AnimationStream.</summary>
public PropertyStreamHandle z;
/// <summary>The PropertyStreamHandle used for the X component in the AnimationStream.</summary>
public PropertyStreamHandle w;
/// <summary>
/// Creates a Vector4Property handle representing a property binding on a Component.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="component">The Component owning the parameter.</param>
/// <param name="name">The property name</param>
/// <returns>Returns a Vector4Property handle that represents the new binding.</returns>
public static Vector4Property Bind(Animator animator, Component component, string name)
{
var type = component.GetType();
return new Vector4Property
{
x = animator.BindStreamProperty(component.transform, type, name + ".x"),
y = animator.BindStreamProperty(component.transform, type, name + ".y"),
z = animator.BindStreamProperty(component.transform, type, name + ".z"),
w = animator.BindStreamProperty(component.transform, type, name + ".w")
};
}
/// <summary>
/// Creates a Vector4Property handle for a custom property in the AnimationStream to pass extra data to downstream animation jobs in the graph.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="name">The name of the property.</param>
/// <returns>Returns a Vector4Property handle that represents the new binding.</returns>
public static Vector4Property BindCustom(Animator animator, string name)
{
return new Vector4Property
{
x = animator.BindCustomStreamProperty(name + ".x", CustomStreamPropertyType.Float),
y = animator.BindCustomStreamProperty(name + ".y", CustomStreamPropertyType.Float),
z = animator.BindCustomStreamProperty(name + ".z", CustomStreamPropertyType.Float),
w = animator.BindCustomStreamProperty(name + ".w", CustomStreamPropertyType.Float)
};
}
/// <summary>
/// Gets the property value from a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The Vector4 property value.</returns>
public Vector4 Get(AnimationStream stream) =>
new Vector4(x.GetFloat(stream), y.GetFloat(stream), z.GetFloat(stream), w.GetFloat(stream));
/// <summary>
/// Sets the property value into a stream.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="value">The new Vector4 property value.</param>
public void Set(AnimationStream stream, Vector4 value)
{
x.SetFloat(stream, value.x);
y.SetFloat(stream, value.y);
z.SetFloat(stream, value.z);
w.SetFloat(stream, value.w);
}
}
}

View File

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

View File

@@ -0,0 +1,94 @@
using UnityEngine.Playables;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// This is the base interface for all animation job binders.
/// </summary>
public interface IAnimationJobBinder
{
/// <summary>
/// Creates the animation job.
/// </summary>
/// <param name="animator">The animated hierarchy Animator component.</param>
/// <param name="data">The constraint data.</param>
/// <param name="component">The constraint component.</param>
/// <returns>Returns a new job interface.</returns>
IAnimationJob Create(Animator animator, IAnimationJobData data, Component component = null);
/// <summary>
/// Destroys the animation job.
/// </summary>
/// <param name="job">The animation job to destroy.</param>
void Destroy(IAnimationJob job);
/// <summary>
/// Updates the animation job.
/// </summary>
/// <param name="job">The animation job to update.</param>
/// <param name="data">The constraint data.</param>
void Update(IAnimationJob job, IAnimationJobData data);
/// <summary>
/// Creates an AnimationScriptPlayable with the specified animation job.
/// </summary>
/// <param name="graph">The PlayableGraph that will own the AnimationScriptPlayable.</param>
/// <param name="job">The animation job to use in the AnimationScriptPlayable.</param>
/// <returns>Returns a new AnimationScriptPlayable.</returns>
AnimationScriptPlayable CreatePlayable(PlayableGraph graph, IAnimationJob job);
}
/// <summary>
/// The is the base class for all animation job binders.
/// </summary>
/// <typeparam name="TJob">The constraint job.</typeparam>
/// <typeparam name="TData">The constraint data.</typeparam>
public abstract class AnimationJobBinder<TJob, TData> : IAnimationJobBinder
where TJob : struct, IAnimationJob
where TData : struct, IAnimationJobData
{
/// <summary>
/// Creates the animation job.
/// </summary>
/// <param name="animator">The animated hierarchy Animator component.</param>
/// <param name="data">The constraint data.</param>
/// <param name="component">The constraint component.</param>
/// <returns>Returns a new job interface.</returns>
public abstract TJob Create(Animator animator, ref TData data, Component component);
/// <summary>
/// Destroys the animation job.
/// </summary>
/// <param name="job">The animation job to destroy.</param>
public abstract void Destroy(TJob job);
/// <summary>
/// Updates the animation job.
/// </summary>
/// <param name="job">The animation job to update.</param>
/// <param name="data">The constraint data.</param>
public virtual void Update(TJob job, ref TData data) {}
/// <inheritdoc />
IAnimationJob IAnimationJobBinder.Create(Animator animator, IAnimationJobData data, Component component)
{
Debug.Assert(data is TData);
TData tData = (TData)data;
return Create(animator, ref tData, component);
}
/// <inheritdoc />
void IAnimationJobBinder.Destroy(IAnimationJob job)
{
Debug.Assert(job is TJob);
Destroy((TJob)job);
}
/// <inheritdoc />
void IAnimationJobBinder.Update(IAnimationJob job, IAnimationJobData data)
{
Debug.Assert(data is TData && job is TJob);
TData tData = (TData)data;
Update((TJob)job, ref tData);
}
/// <inheritdoc />
AnimationScriptPlayable IAnimationJobBinder.CreatePlayable(PlayableGraph graph, IAnimationJob job)
{
Debug.Assert(job is TJob);
return AnimationScriptPlayable.Create(graph, (TJob)job);
}
}
}

View File

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

View File

@@ -0,0 +1,18 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// This interface is used to represent all constraint data structs.
/// </summary>
public interface IAnimationJobData
{
/// <summary>
/// Retrieves the data valid state.
/// </summary>
/// <returns>Returns true if data can be successfully used in a constraint. Returns false otherwise.</returns>
bool IsValid();
/// <summary>
/// Resets values to defaults.
/// </summary>
void SetDefaultValues();
}
}

View File

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

View File

@@ -0,0 +1,11 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// This interface represents an animation job with a weight value.
/// </summary>
public interface IWeightedAnimationJob : IAnimationJob
{
/// <summary>The main weight given to the constraint. This is a value in between 0 and 1.</summary>
FloatProperty jobWeight { get; set; }
}
}

View File

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

View File

@@ -0,0 +1,355 @@
using System;
using Unity.Collections;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The MultiAim constraint job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct MultiAimConstraintJob : IWeightedAnimationJob
{
const float k_Epsilon = 1e-5f;
/// <summary>
/// Specifies how the world up vector used by the Multi-Aim constraint is defined.
/// </summary>
public enum WorldUpType
{
/// <summary>Neither defines nor uses a world up vector.</summary>
None,
/// <summary>Uses and defines the world up vector as the Unity Scene up vector (the Y axis).</summary>
SceneUp,
/// <summary>Uses and defines the world up vector as a vector from the constrained object, in the direction of the up object.</summary>
ObjectUp,
/// <summary>Uses and defines the world up vector as relative to the local space of the object.</summary>
ObjectRotationUp,
/// <summary>Uses and defines the world up vector as a vector specified by the user.</summary>
Vector
};
/// <summary>The Transform handle for the constrained object Transform.</summary>
public ReadWriteTransformHandle driven;
/// <summary>The Transform handle for the constrained object parent Transform.</summary>
public ReadOnlyTransformHandle drivenParent;
/// <summary>The post-rotation offset applied to the constrained object.</summary>
public Vector3Property drivenOffset;
/// <summary>List of Transform handles for the source objects.</summary>
public NativeArray<ReadOnlyTransformHandle> sourceTransforms;
/// <summary>List of weights for the source objects.</summary>
public NativeArray<PropertyStreamHandle> sourceWeights;
/// <summary>List of offsets to apply to source rotations if maintainOffset is enabled.</summary>
public NativeArray<Quaternion> sourceOffsets;
/// <summary>Buffer used to store weights during job execution.</summary>
public NativeArray<float> weightBuffer;
/// <summary>Local aim axis of the constrained object Transform.</summary>
public Vector3 aimAxis;
/// <summary>Local up axis of the constrained object Transform.</summary>
public Vector3 upAxis;
/// <summary>
/// Specifies which mode to use to keep the upward direction of the constrained Object.
/// </summary>
public WorldUpType worldUpType;
/// <summary>
/// A static vector in world coordinates that is the general upward direction. This is used when World Up Type is set to WorldUpType.Vector.
/// </summary>
public Vector3 worldUpAxis;
/// <summary>
/// The Transform handle for the world up object. This is used when World Up Type is set to WorldUpType.ObjectUp or WorldUpType.ObjectRotationUp.
/// </summary>
public ReadOnlyTransformHandle worldUpObject;
/// <summary>Axes mask. Rotation will apply on the local axis for a value of 1.0, and will be kept as is for a value of 0.0.</summary>
public Vector3 axesMask;
/// <summary>Minimum rotation value.</summary>
public FloatProperty minLimit;
/// <summary>Maximum rotation value.</summary>
public FloatProperty maxLimit;
/// <inheritdoc />
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
AnimationStreamHandleUtility.ReadFloats(stream, sourceWeights, weightBuffer);
float sumWeights = AnimationRuntimeUtils.Sum(weightBuffer);
if (sumWeights < k_Epsilon)
{
AnimationRuntimeUtils.PassThrough(stream, driven);
return;
}
var weightScale = sumWeights > 1f ? 1f / sumWeights : 1f;
var drivenParentInvRot = Quaternion.Inverse(drivenParent.GetRotation(stream));
var drivenParentInvWorldMatrix = Matrix4x4.Inverse(drivenParent.GetLocalToWorldMatrix(stream));
var accumWeights = 0f;
var accumDeltaRot = QuaternionExt.zero;
var drivenWPos = driven.GetPosition(stream);
var drivenLRot = driven.GetLocalRotation(stream);
var worldUpVector = ComputeWorldUpVector(stream);
var upVector = AnimationRuntimeUtils.Select(Vector3.zero, upAxis, axesMask);
var hasMasks = Vector3.Dot(axesMask, axesMask) < 3f;
var hasUpAxisCorrection = worldUpType != WorldUpType.None && Vector3.Dot(upVector, upVector) > k_Epsilon;
var minMaxAngles = new Vector2(minLimit.Get(stream), maxLimit.Get(stream));
for (int i = 0; i < sourceTransforms.Length; ++i)
{
var normalizedWeight = weightBuffer[i] * weightScale;
if (normalizedWeight < k_Epsilon)
continue;
var sourceTransform = sourceTransforms[i];
var fromDir = drivenLRot * aimAxis;
var toDir = drivenParentInvWorldMatrix.MultiplyVector(sourceTransform.GetPosition(stream) - drivenWPos);
if (toDir.sqrMagnitude < k_Epsilon)
continue;
var crossDir = Vector3.Cross(fromDir, toDir).normalized;
if (hasMasks)
{
crossDir = AnimationRuntimeUtils.Select(Vector3.zero, crossDir, axesMask).normalized;
if (Vector3.Dot(crossDir, crossDir) > k_Epsilon)
{
fromDir = AnimationRuntimeUtils.ProjectOnPlane(fromDir, crossDir);
toDir = AnimationRuntimeUtils.ProjectOnPlane(toDir, crossDir);
}
else
{
toDir = fromDir;
}
}
var rotToSource = Quaternion.AngleAxis(
Mathf.Clamp(Vector3.Angle(fromDir, toDir), minMaxAngles.x, minMaxAngles.y),
crossDir
);
if (hasUpAxisCorrection)
{
var wupProject = Vector3.Cross(Vector3.Cross(drivenParentInvRot * worldUpVector, toDir).normalized, toDir).normalized;
var rupProject = Vector3.Cross(Vector3.Cross(rotToSource * drivenLRot * upVector, toDir).normalized, toDir).normalized;
rotToSource = QuaternionExt.FromToRotation(rupProject, wupProject) * rotToSource;
}
accumDeltaRot = QuaternionExt.Add(
accumDeltaRot,
QuaternionExt.Scale(sourceOffsets[i] * rotToSource, normalizedWeight)
);
// Required to update handles with binding info.
sourceTransforms[i] = sourceTransform;
accumWeights += normalizedWeight;
}
accumDeltaRot = QuaternionExt.NormalizeSafe(accumDeltaRot);
if (accumWeights < 1f)
accumDeltaRot = Quaternion.Lerp(Quaternion.identity, accumDeltaRot, accumWeights);
var newRot = accumDeltaRot * drivenLRot;
if (hasMasks)
newRot = Quaternion.Euler(AnimationRuntimeUtils.Select(drivenLRot.eulerAngles, newRot.eulerAngles, axesMask));
var offset = drivenOffset.Get(stream);
if (Vector3.Dot(offset, offset) > 0f)
newRot *= Quaternion.Euler(offset);
driven.SetLocalRotation(stream, Quaternion.Lerp(drivenLRot, newRot, w));
}
else
AnimationRuntimeUtils.PassThrough(stream, driven);
}
Vector3 ComputeWorldUpVector(AnimationStream stream)
{
var result = Vector3.up;
switch (worldUpType)
{
case WorldUpType.None:
result = Vector3.zero;
break;
case WorldUpType.SceneUp:
// the scene Up vector and the World Up vector are the same thing
break;
case WorldUpType.ObjectUp:
{
// the target's Up vector points to the up object
var referencePos = Vector3.zero;
if (worldUpObject.IsValid(stream))
referencePos = worldUpObject.GetPosition(stream);
var targetPos = driven.GetPosition(stream);
result = (referencePos - targetPos).normalized;
break;
}
case WorldUpType.ObjectRotationUp:
{
var upRotation = Quaternion.identity;
if (worldUpObject.IsValid(stream))
upRotation = worldUpObject.GetRotation(stream);
// if no object is specified, the up vector is defined relative to the scene world space
result = upRotation * worldUpAxis;
break;
}
case WorldUpType.Vector:
result = worldUpAxis;
break;
default:
break;
}
return result;
}
}
/// <summary>
/// This interface defines the data mapping for the MultiAim constraint.
/// </summary>
public interface IMultiAimConstraintData
{
/// <summary>The Transform affected by the constraint Source Transforms.</summary>
Transform constrainedObject { get; }
/// <summary>
/// The list of Transforms that influence the constrained Transform orientation.
/// Each source has a weight from 0 to 1.
/// </summary>
WeightedTransformArray sourceObjects { get; }
/// <summary>
/// This is used to maintain the current rotation offset from the constrained GameObject to the source GameObjects.
/// </summary>
bool maintainOffset { get; }
/// <summary>Specifies the local aim axis of the constrained Transform to use in order to orient itself to the Source Transforms.</summary>
Vector3 aimAxis { get; }
/// <summary>Specified the local up axis of the constrained Transform to use in order to orient itself to the Source Transforms.</summary>
Vector3 upAxis { get; }
/// <summary>
/// Specifies which mode to use to keep the upward direction of the constrained Object.
/// </summary>
/// <seealso cref="MultiAimConstraintJob.WorldUpType"/>
int worldUpType { get; }
/// <summary>
/// A static vector in world coordinates that is the general upward direction. This is used when World Up Type is set to WorldUpType.Vector.
/// </summary>
Vector3 worldUpAxis { get; }
/// <summary>
/// The Transform used to calculate the upward direction. This is used when World Up Type is set to WorldUpType.ObjectUp or WorldUpType.ObjectRotationUp.
/// </summary>
Transform worldUpObject { get; }
/// <summary>Toggles whether the constrained Transform will rotate along the X axis.</summary>
bool constrainedXAxis { get; }
/// <summary>Toggles whether the constrained Transform will rotate along the Y axis.</summary>
bool constrainedYAxis { get; }
/// <summary>Toggles whether the constrained Transform will rotate along the Z axis.</summary>
bool constrainedZAxis { get; }
/// <summary>The path to the offset property in the constraint component.</summary>
string offsetVector3Property { get; }
/// <summary>The path to the minimum limit property in the constraint component.</summary>
string minLimitFloatProperty { get; }
/// <summary>The path to the maximum limit property in the constraint component.</summary>
string maxLimitFloatProperty { get; }
/// <summary>The path to the source objects property in the constraint component.</summary>
string sourceObjectsProperty { get; }
}
/// <summary>
/// The MultiAim constraint job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class MultiAimConstraintJobBinder<T> : AnimationJobBinder<MultiAimConstraintJob, T>
where T : struct, IAnimationJobData, IMultiAimConstraintData
{
/// <inheritdoc />
public override MultiAimConstraintJob Create(Animator animator, ref T data, Component component)
{
var job = new MultiAimConstraintJob();
job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject);
job.drivenParent = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject.parent);
job.aimAxis = data.aimAxis;
job.upAxis = data.upAxis;
job.worldUpType = (MultiAimConstraintJob.WorldUpType)data.worldUpType;
job.worldUpAxis = data.worldUpAxis;
if (data.worldUpObject != null)
job.worldUpObject = ReadOnlyTransformHandle.Bind(animator, data.worldUpObject);
WeightedTransformArray sourceObjects = data.sourceObjects;
WeightedTransformArrayBinder.BindReadOnlyTransforms(animator, component, sourceObjects, out job.sourceTransforms);
WeightedTransformArrayBinder.BindWeights(animator, component, sourceObjects, data.sourceObjectsProperty, out job.sourceWeights);
job.sourceOffsets = new NativeArray<Quaternion>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.weightBuffer = new NativeArray<float>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
for (int i = 0; i < sourceObjects.Count; ++i)
{
if (data.maintainOffset)
{
var constrainedAim = data.constrainedObject.rotation * data.aimAxis;
job.sourceOffsets[i] = QuaternionExt.FromToRotation(
sourceObjects[i].transform.position - data.constrainedObject.position,
constrainedAim
);
}
else
job.sourceOffsets[i] = Quaternion.identity;
}
job.minLimit = FloatProperty.Bind(animator, component, data.minLimitFloatProperty);
job.maxLimit = FloatProperty.Bind(animator, component, data.maxLimitFloatProperty);
job.drivenOffset = Vector3Property.Bind(animator, component, data.offsetVector3Property);
job.axesMask = new Vector3(
System.Convert.ToSingle(data.constrainedXAxis),
System.Convert.ToSingle(data.constrainedYAxis),
System.Convert.ToSingle(data.constrainedZAxis)
);
return job;
}
/// <inheritdoc />
public override void Destroy(MultiAimConstraintJob job)
{
job.sourceTransforms.Dispose();
job.sourceWeights.Dispose();
job.sourceOffsets.Dispose();
job.weightBuffer.Dispose();
}
}
}

View File

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

View File

@@ -0,0 +1,222 @@
using Unity.Collections;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The MultiParent constraint job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct MultiParentConstraintJob : IWeightedAnimationJob
{
const float k_Epsilon = 1e-5f;
/// <summary>The Transform handle for the constrained object Transform.</summary>
public ReadWriteTransformHandle driven;
/// <summary>The Transform handle for the constrained object parent Transform.</summary>
public ReadOnlyTransformHandle drivenParent;
/// <summary>List of Transform handles for the source objects.</summary>
public NativeArray<ReadOnlyTransformHandle> sourceTransforms;
/// <summary>List of weights for the source objects.</summary>
public NativeArray<PropertyStreamHandle> sourceWeights;
/// <summary>List of offsets to apply to source rotations if maintainOffset is enabled.</summary>
public NativeArray<AffineTransform> sourceOffsets;
/// <summary>Buffer used to store weights during job execution.</summary>
public NativeArray<float> weightBuffer;
/// <summary>Position axes mask. Position will apply on the local axis for a value of 1.0, and will be kept as is for a value of 0.0.</summary>
public Vector3 positionAxesMask;
/// <summary>Rotation axes mask. Rotation will apply on the local axis for a value of 1.0, and will be kept as is for a value of 0.0.</summary>
public Vector3 rotationAxesMask;
/// <summary>The main weight given to the constraint. This is a value in between 0 and 1.</summary>
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
AnimationStreamHandleUtility.ReadFloats(stream, sourceWeights, weightBuffer);
float sumWeights = AnimationRuntimeUtils.Sum(weightBuffer);
if (sumWeights < k_Epsilon)
{
AnimationRuntimeUtils.PassThrough(stream, driven);
return;
}
float weightScale = sumWeights > 1f ? 1f / sumWeights : 1f;
float accumWeights = 0f;
var accumTx = new AffineTransform(Vector3.zero, QuaternionExt.zero);
for (int i = 0; i < sourceTransforms.Length; ++i)
{
ReadOnlyTransformHandle sourceTransform = sourceTransforms[i];
var normalizedWeight = weightBuffer[i] * weightScale;
if (normalizedWeight < k_Epsilon)
continue;
sourceTransform.GetGlobalTR(stream, out Vector3 srcWPos, out Quaternion srcWRot);
var sourceTx = new AffineTransform(srcWPos, srcWRot);
sourceTx *= sourceOffsets[i];
accumTx.translation += sourceTx.translation * normalizedWeight;
accumTx.rotation = QuaternionExt.Add(accumTx.rotation, QuaternionExt.Scale(sourceTx.rotation, normalizedWeight));
// Required to update handles with binding info.
sourceTransforms[i] = sourceTransform;
accumWeights += normalizedWeight;
}
driven.GetGlobalTR(stream, out Vector3 currentWPos, out Quaternion currentWRot);
var drivenTx = new AffineTransform(currentWPos, currentWRot);
accumTx.rotation = QuaternionExt.NormalizeSafe(accumTx.rotation);
if (accumWeights < 1f)
{
accumTx.translation += currentWPos * (1f - accumWeights);
accumTx.rotation = Quaternion.Lerp(currentWRot, accumTx.rotation, accumWeights);
}
var parentTx = AffineTransform.identity;
// Convert accumTx and drivenTx to local space
if (drivenParent.IsValid(stream))
{
drivenParent.GetGlobalTR(stream, out Vector3 parentWPos, out Quaternion parentWRot);
parentTx = new AffineTransform(parentWPos, parentWRot);
accumTx = parentTx.InverseMul(accumTx);
drivenTx = parentTx.InverseMul(drivenTx);
}
if (Vector3.Dot(positionAxesMask, positionAxesMask) < 3f)
accumTx.translation = AnimationRuntimeUtils.Lerp(drivenTx.translation, accumTx.translation, positionAxesMask);
if (Vector3.Dot(rotationAxesMask, rotationAxesMask) < 3f)
accumTx.rotation = Quaternion.Euler(AnimationRuntimeUtils.Lerp(drivenTx.rotation.eulerAngles, accumTx.rotation.eulerAngles, rotationAxesMask));
// Convert accumTx back to world space
accumTx = parentTx * accumTx;
driven.SetGlobalTR(
stream,
Vector3.Lerp(currentWPos, accumTx.translation, w),
Quaternion.Lerp(currentWRot, accumTx.rotation, w)
);
}
else
AnimationRuntimeUtils.PassThrough(stream, driven);
}
}
/// <summary>
/// This interface defines the data mapping for the MultiParent constraint.
/// </summary>
public interface IMultiParentConstraintData
{
/// <summary>The Transform affected by the constraint Source Transforms.</summary>
Transform constrainedObject { get; }
/// <summary>
/// The list of Transforms that influence the constrained Transform rotation.
/// Each source has a weight from 0 to 1.
/// </summary>
WeightedTransformArray sourceObjects { get; }
/// <summary>This is used to maintain the current position offset from the constrained GameObject to the source GameObjects.</summary>
bool maintainPositionOffset { get; }
/// <summary>This is used to maintain the current rotation offset from the constrained GameObject to the source GameObjects.</summary>
bool maintainRotationOffset { get; }
/// <summary>Toggles whether the constrained transform will translate along the X axis.</summary>
bool constrainedPositionXAxis { get; }
/// <summary>Toggles whether the constrained transform will translate along the Y axis.</summary>
bool constrainedPositionYAxis { get; }
/// <summary>Toggles whether the constrained transform will translate along the Z axis.</summary>
bool constrainedPositionZAxis { get; }
/// <summary>Toggles whether the constrained transform will rotate along the X axis.</summary>
bool constrainedRotationXAxis { get; }
/// <summary>Toggles whether the constrained transform will rotate along the Y axis.</summary>
bool constrainedRotationYAxis { get; }
/// <summary>Toggles whether the constrained transform will rotate along the Z axis.</summary>
bool constrainedRotationZAxis { get; }
/// <summary>The path to the source objects property in the constraint component.</summary>
string sourceObjectsProperty { get; }
}
/// <summary>
/// The MultiParent constraint job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class MultiParentConstraintJobBinder<T> : AnimationJobBinder<MultiParentConstraintJob, T>
where T : struct, IAnimationJobData, IMultiParentConstraintData
{
/// <inheritdoc />
public override MultiParentConstraintJob Create(Animator animator, ref T data, Component component)
{
var job = new MultiParentConstraintJob();
job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject);
job.drivenParent = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject.parent);
WeightedTransformArray sourceObjects = data.sourceObjects;
WeightedTransformArrayBinder.BindReadOnlyTransforms(animator, component, sourceObjects, out job.sourceTransforms);
WeightedTransformArrayBinder.BindWeights(animator, component, sourceObjects, data.sourceObjectsProperty, out job.sourceWeights);
job.sourceOffsets = new NativeArray<AffineTransform>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.weightBuffer = new NativeArray<float>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
var drivenTx = new AffineTransform(data.constrainedObject.position, data.constrainedObject.rotation);
for (int i = 0; i < sourceObjects.Count; ++i)
{
var sourceTransform = sourceObjects[i].transform;
var srcTx = new AffineTransform(sourceTransform.position, sourceTransform.rotation);
var srcOffset = AffineTransform.identity;
var tmp = srcTx.InverseMul(drivenTx);
if (data.maintainPositionOffset)
srcOffset.translation = tmp.translation;
if (data.maintainRotationOffset)
srcOffset.rotation = tmp.rotation;
job.sourceOffsets[i] = srcOffset;
}
job.positionAxesMask = new Vector3(
System.Convert.ToSingle(data.constrainedPositionXAxis),
System.Convert.ToSingle(data.constrainedPositionYAxis),
System.Convert.ToSingle(data.constrainedPositionZAxis)
);
job.rotationAxesMask = new Vector3(
System.Convert.ToSingle(data.constrainedRotationXAxis),
System.Convert.ToSingle(data.constrainedRotationYAxis),
System.Convert.ToSingle(data.constrainedRotationZAxis)
);
return job;
}
/// <inheritdoc />
public override void Destroy(MultiParentConstraintJob job)
{
job.sourceTransforms.Dispose();
job.sourceWeights.Dispose();
job.sourceOffsets.Dispose();
job.weightBuffer.Dispose();
}
}
}

View File

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

View File

@@ -0,0 +1,180 @@
using Unity.Collections;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The MultiPosition constraint job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct MultiPositionConstraintJob : IWeightedAnimationJob
{
const float k_Epsilon = 1e-5f;
/// <summary>The Transform handle for the constrained object Transform.</summary>
public ReadWriteTransformHandle driven;
/// <summary>The Transform handle for the constrained object parent Transform.</summary>
public ReadOnlyTransformHandle drivenParent;
/// <summary>The post-translation offset applied to the constrained object.</summary>
public Vector3Property drivenOffset;
/// <summary>List of Transform handles for the source objects.</summary>
public NativeArray<ReadOnlyTransformHandle> sourceTransforms;
/// <summary>List of weights for the source objects.</summary>
public NativeArray<PropertyStreamHandle> sourceWeights;
/// <summary>List of offsets to apply to source rotations if maintainOffset is enabled.</summary>
public NativeArray<Vector3> sourceOffsets;
/// <summary>Buffer used to store weights during job execution.</summary>
public NativeArray<float> weightBuffer;
/// <summary>Axes mask. Rotation will apply on the local axis for a value of 1.0, and will be kept as is for a value of 0.0.</summary>
public Vector3 axesMask;
/// <inheritdoc />
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
AnimationStreamHandleUtility.ReadFloats(stream, sourceWeights, weightBuffer);
float sumWeights = AnimationRuntimeUtils.Sum(weightBuffer);
if (sumWeights < k_Epsilon)
{
AnimationRuntimeUtils.PassThrough(stream, driven);
return;
}
float weightScale = sumWeights > 1f ? 1f / sumWeights : 1f;
var currentWPos = driven.GetPosition(stream);
var drivenPos = currentWPos;
Vector3 accumPos = currentWPos;
for (int i = 0; i < sourceTransforms.Length; ++i)
{
var normalizedWeight = weightBuffer[i] * weightScale;
if (normalizedWeight < k_Epsilon)
continue;
ReadOnlyTransformHandle sourceTransform = sourceTransforms[i];
accumPos += (sourceTransform.GetPosition(stream) + sourceOffsets[i] - currentWPos) * normalizedWeight;
// Required to update handles with binding info.
sourceTransforms[i] = sourceTransform;
}
var parentTx = AffineTransform.identity;
// Convert accumPos and drivenPos to local space
if (drivenParent.IsValid(stream))
{
drivenParent.GetGlobalTR(stream, out Vector3 parentWPos, out Quaternion parentWRot);
parentTx = new AffineTransform(parentWPos, parentWRot);
accumPos = parentTx.InverseTransform(accumPos);
drivenPos = parentTx.InverseTransform(drivenPos);
}
if (Vector3.Dot(axesMask, axesMask) < 3f)
accumPos = AnimationRuntimeUtils.Lerp(drivenPos, accumPos, axesMask);
// Convert accumPos back to world space
accumPos = parentTx * (accumPos + drivenOffset.Get(stream));
driven.SetPosition(stream, Vector3.Lerp(currentWPos, accumPos, w));
}
else
AnimationRuntimeUtils.PassThrough(stream, driven);
}
}
/// <summary>
/// This interface defines the data mapping for the MultiPosition constraint.
/// </summary>
public interface IMultiPositionConstraintData
{
/// <summary>The Transform affected by the constraint Source Transforms.</summary>
Transform constrainedObject { get; }
/// <summary>
/// The list of Transforms that influence the constrained Transform position.
/// Each source has a weight from 0 to 1.
/// </summary>
WeightedTransformArray sourceObjects { get; }
/// <summary>This is used to maintain the current position offset from the constrained GameObject to the source GameObjects.</summary>
bool maintainOffset { get; }
/// <summary>The path to the offset property in the constraint component.</summary>
string offsetVector3Property { get; }
/// <summary>The path to the source objects property in the constraint component.</summary>
string sourceObjectsProperty { get; }
/// <summary>Toggles whether the constrained transform will translate along the X axis.</summary>
bool constrainedXAxis { get; }
/// <summary>Toggles whether the constrained transform will translate along the Y axis.</summary>
bool constrainedYAxis { get; }
/// <summary>Toggles whether the constrained transform will translate along the Z axis.</summary>
bool constrainedZAxis { get; }
}
/// <summary>
/// The MultiPosition constraint job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class MultiPositionConstraintJobBinder<T> : AnimationJobBinder<MultiPositionConstraintJob, T>
where T : struct, IAnimationJobData, IMultiPositionConstraintData
{
/// <inheritdoc />
public override MultiPositionConstraintJob Create(Animator animator, ref T data, Component component)
{
var job = new MultiPositionConstraintJob();
job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject);
job.drivenParent = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject.parent);
job.drivenOffset = Vector3Property.Bind(animator, component, data.offsetVector3Property);
WeightedTransformArray sourceObjects = data.sourceObjects;
WeightedTransformArrayBinder.BindReadOnlyTransforms(animator, component, sourceObjects, out job.sourceTransforms);
WeightedTransformArrayBinder.BindWeights(animator, component, sourceObjects, data.sourceObjectsProperty, out job.sourceWeights);
job.sourceOffsets = new NativeArray<Vector3>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.weightBuffer = new NativeArray<float>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
Vector3 drivenPos = data.constrainedObject.position;
for (int i = 0; i < sourceObjects.Count; ++i)
{
job.sourceOffsets[i] = data.maintainOffset ? (drivenPos - sourceObjects[i].transform.position) : Vector3.zero;
}
job.axesMask = new Vector3(
System.Convert.ToSingle(data.constrainedXAxis),
System.Convert.ToSingle(data.constrainedYAxis),
System.Convert.ToSingle(data.constrainedZAxis)
);
return job;
}
/// <inheritdoc />
public override void Destroy(MultiPositionConstraintJob job)
{
job.sourceTransforms.Dispose();
job.sourceWeights.Dispose();
job.sourceOffsets.Dispose();
job.weightBuffer.Dispose();
}
}
}

View File

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

View File

@@ -0,0 +1,141 @@
using Unity.Collections;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The MultiReferential constraint job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct MultiReferentialConstraintJob : IWeightedAnimationJob
{
/// <summary>The driver index.</summary>
public IntProperty driver;
/// <summary>The list of Transforms that are affected by the specified driver.</summary>
public NativeArray<ReadWriteTransformHandle> sources;
/// <summary>Cache of AffineTransform representing the source objects initial positions.</summary>
public NativeArray<AffineTransform> sourceBindTx;
/// <summary>List of AffineTransform to apply to driven source objects.</summary>
public NativeArray<AffineTransform> offsetTx;
private int m_PrevDriverIdx;
/// <inheritdoc />
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
var driverIdx = driver.Get(stream);
if (driverIdx != m_PrevDriverIdx)
UpdateOffsets(driverIdx);
sources[driverIdx].GetGlobalTR(stream, out Vector3 driverWPos, out Quaternion driverWRot);
var driverTx = new AffineTransform(driverWPos, driverWRot);
int offset = 0;
for (int i = 0; i < sources.Length; ++i)
{
if (i == driverIdx)
continue;
var tx = driverTx * offsetTx[offset];
var src = sources[i];
src.GetGlobalTR(stream, out Vector3 srcWPos, out Quaternion srcWRot);
src.SetGlobalTR(stream, Vector3.Lerp(srcWPos, tx.translation, w), Quaternion.Lerp(srcWRot, tx.rotation, w));
offset++;
sources[i] = src;
}
AnimationRuntimeUtils.PassThrough(stream, sources[driverIdx]);
}
else
{
for (int i = 0; i < sources.Length; ++i)
AnimationRuntimeUtils.PassThrough(stream, sources[i]);
}
}
internal void UpdateOffsets(int driver)
{
driver = Mathf.Clamp(driver, 0, sources.Length - 1);
int offset = 0;
var invDriverTx = sourceBindTx[driver].Inverse();
for (int i = 0; i < sourceBindTx.Length; ++i)
{
if (i == driver)
continue;
offsetTx[offset] = invDriverTx * sourceBindTx[i];
offset++;
}
m_PrevDriverIdx = driver;
}
}
/// <summary>
/// This interface defines the data mapping for the MultiReferential constraint.
/// </summary>
public interface IMultiReferentialConstraintData
{
/// <summary>The driver index. This is a value in between 0 and the number of sourceObjects.</summary>
int driverValue { get; }
/// <summary>The path to the driver property in the constraint component.</summary>
string driverIntProperty { get; }
/// <summary>The list of Transforms that can act as drivers for the constrained Transform.</summary>
Transform[] sourceObjects { get; }
}
/// <summary>
/// The MultiReferential constraint job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class MultiReferentialConstraintJobBinder<T> : AnimationJobBinder<MultiReferentialConstraintJob, T>
where T : struct, IAnimationJobData, IMultiReferentialConstraintData
{
/// <inheritdoc />
public override MultiReferentialConstraintJob Create(Animator animator, ref T data, Component component)
{
var job = new MultiReferentialConstraintJob();
var sources = data.sourceObjects;
job.driver = IntProperty.Bind(animator, component, data.driverIntProperty);
job.sources = new NativeArray<ReadWriteTransformHandle>(sources.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.sourceBindTx = new NativeArray<AffineTransform>(sources.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.offsetTx = new NativeArray<AffineTransform>(sources.Length - 1, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
for (int i = 0; i < sources.Length; ++i)
{
job.sources[i] = ReadWriteTransformHandle.Bind(animator, sources[i].transform);
job.sourceBindTx[i] = new AffineTransform(sources[i].position, sources[i].rotation);
}
job.UpdateOffsets(data.driverValue);
return job;
}
/// <inheritdoc />
public override void Destroy(MultiReferentialConstraintJob job)
{
job.sources.Dispose();
job.sourceBindTx.Dispose();
job.offsetTx.Dispose();
}
}
}

View File

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

View File

@@ -0,0 +1,180 @@
using Unity.Collections;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The MultiRotation constraint job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct MultiRotationConstraintJob : IWeightedAnimationJob
{
const float k_Epsilon = 1e-5f;
/// <summary>The Transform handle for the constrained object Transform.</summary>
public ReadWriteTransformHandle driven;
/// <summary>The Transform handle for the constrained object parent Transform.</summary>
public ReadOnlyTransformHandle drivenParent;
/// <summary>The post-rotation offset applied to the constrained object.</summary>
public Vector3Property drivenOffset;
/// <summary>List of Transform handles for the source objects.</summary>
public NativeArray<ReadOnlyTransformHandle> sourceTransforms;
/// <summary>List of weights for the source objects.</summary>
public NativeArray<PropertyStreamHandle> sourceWeights;
/// <summary>List of offsets to apply to source rotations if maintainOffset is enabled.</summary>
public NativeArray<Quaternion> sourceOffsets;
/// <summary>Buffer used to store weights during job execution.</summary>
public NativeArray<float> weightBuffer;
/// <summary>Axes mask. Rotation will apply on the local axis for a value of 1.0, and will be kept as is for a value of 0.0.</summary>
public Vector3 axesMask;
/// <inheritdoc />
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
AnimationStreamHandleUtility.ReadFloats(stream, sourceWeights, weightBuffer);
float sumWeights = AnimationRuntimeUtils.Sum(weightBuffer);
if (sumWeights < k_Epsilon)
{
AnimationRuntimeUtils.PassThrough(stream, driven);
return;
}
float weightScale = sumWeights > 1f ? 1f / sumWeights : 1f;
float accumWeights = 0f;
Quaternion accumRot = QuaternionExt.zero;
for (int i = 0; i < sourceTransforms.Length; ++i)
{
var normalizedWeight = weightBuffer[i] * weightScale;
if (normalizedWeight < k_Epsilon)
continue;
ReadOnlyTransformHandle sourceTransform = sourceTransforms[i];
accumRot = QuaternionExt.Add(accumRot, QuaternionExt.Scale(sourceTransform.GetRotation(stream) * sourceOffsets[i], normalizedWeight));
// Required to update handles with binding info.
sourceTransforms[i] = sourceTransform;
accumWeights += normalizedWeight;
}
accumRot = QuaternionExt.NormalizeSafe(accumRot);
if (accumWeights < 1f)
accumRot = Quaternion.Lerp(driven.GetRotation(stream), accumRot, accumWeights);
// Convert accumRot to local space
if (drivenParent.IsValid(stream))
accumRot = Quaternion.Inverse(drivenParent.GetRotation(stream)) * accumRot;
Quaternion currentLRot = driven.GetLocalRotation(stream);
if (Vector3.Dot(axesMask, axesMask) < 3f)
accumRot = Quaternion.Euler(AnimationRuntimeUtils.Lerp(currentLRot.eulerAngles, accumRot.eulerAngles, axesMask));
var offset = drivenOffset.Get(stream);
if (Vector3.Dot(offset, offset) > 0f)
accumRot *= Quaternion.Euler(offset);
driven.SetLocalRotation(stream, Quaternion.Lerp(currentLRot, accumRot, w));
}
else
AnimationRuntimeUtils.PassThrough(stream, driven);
}
}
/// <summary>
/// This interface defines the data mapping for the MultiRotation constraint.
/// </summary>
public interface IMultiRotationConstraintData
{
/// <summary>The Transform affected by the constraint Source Transforms.</summary>
Transform constrainedObject { get; }
/// <summary>
/// The list of Transforms that influence the constrained Transform rotation.
/// Each source has a weight from 0 to 1.
/// </summary>
WeightedTransformArray sourceObjects { get; }
/// <summary>This is used to maintain the current rotation offset from the constrained GameObject to the source GameObjects.</summary>
bool maintainOffset { get; }
/// <summary>The path to the offset property in the constraint component.</summary>
string offsetVector3Property { get; }
/// <summary>The path to the source objects property in the constraint component.</summary>
string sourceObjectsProperty { get; }
/// <summary>Toggles whether the constrained transform will rotate along the X axis.</summary>
bool constrainedXAxis { get; }
/// <summary>Toggles whether the constrained transform will rotate along the Y axis.</summary>
bool constrainedYAxis { get; }
/// <summary>Toggles whether the constrained transform will rotate along the Z axis.</summary>
bool constrainedZAxis { get; }
}
/// <summary>
/// The MultiRotation constraint job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class MultiRotationConstraintJobBinder<T> : AnimationJobBinder<MultiRotationConstraintJob, T>
where T : struct, IAnimationJobData, IMultiRotationConstraintData
{
/// <inheritdoc />
public override MultiRotationConstraintJob Create(Animator animator, ref T data, Component component)
{
var job = new MultiRotationConstraintJob();
job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject);
job.drivenParent = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject.parent);
job.drivenOffset = Vector3Property.Bind(animator, component, data.offsetVector3Property);
WeightedTransformArray sourceObjects = data.sourceObjects;
WeightedTransformArrayBinder.BindReadOnlyTransforms(animator, component, sourceObjects, out job.sourceTransforms);
WeightedTransformArrayBinder.BindWeights(animator, component, sourceObjects, data.sourceObjectsProperty, out job.sourceWeights);
job.sourceOffsets = new NativeArray<Quaternion>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.weightBuffer = new NativeArray<float>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
Quaternion drivenRot = data.constrainedObject.rotation;
for (int i = 0; i < sourceObjects.Count; ++i)
{
job.sourceOffsets[i] = data.maintainOffset ?
(Quaternion.Inverse(sourceObjects[i].transform.rotation) * drivenRot) : Quaternion.identity;
}
job.axesMask = new Vector3(
System.Convert.ToSingle(data.constrainedXAxis),
System.Convert.ToSingle(data.constrainedYAxis),
System.Convert.ToSingle(data.constrainedZAxis)
);
return job;
}
/// <inheritdoc />
public override void Destroy(MultiRotationConstraintJob job)
{
job.sourceTransforms.Dispose();
job.sourceWeights.Dispose();
job.sourceOffsets.Dispose();
job.weightBuffer.Dispose();
}
}
}

View File

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

View File

@@ -0,0 +1,241 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The OverrideTransform job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct OverrideTransformJob : IWeightedAnimationJob
{
/// <summary>
/// The override space controls how the override source Transform
/// is copied unto constrained Transform.
/// </summary>
public enum Space
{
/// <summary>Copy override world TR components into world TR components of the constrained Transform.</summary>
World = 0,
/// <summary>Copy override local TR components into local TR components of the constrained Transform.</summary>
Local = 1,
/// <summary>Add override local TR components to local TR components of the constrained Transform. </summary>
Pivot = 2
}
/// <summary>The Transform handle for the constrained object Transform.</summary>
public ReadWriteTransformHandle driven;
/// <summary>The Transform handle for the override source object Transform.</summary>
public ReadOnlyTransformHandle source;
/// <summary>Cached inverse local TR used in space switching calculations.</summary>
public AffineTransform sourceInvLocalBindTx;
/// <summary>Cached source to world coordinates quaternion. Used when Space is set to World.</summary>
public Quaternion sourceToWorldRot;
/// <summary>Cached source to local coordinates quaternion. Used when Space is set to Local.</summary>
public Quaternion sourceToLocalRot;
/// <summary>Cached source to pivot coordinates quaternion. Used when Space is set to Pivot.</summary>
public Quaternion sourceToPivotRot;
/// <summary>CacheIndex to the override space.</summary>
/// <seealso cref="AnimationJobCache"/>
public CacheIndex spaceIdx;
/// <summary>CacheIndex to source to space quaternion used in current space.</summary>
/// <seealso cref="AnimationJobCache"/>
public CacheIndex sourceToCurrSpaceRotIdx;
/// <summary>The override position.</summary>
public Vector3Property position;
/// <summary>The override rotation.</summary>
public Vector3Property rotation;
/// <summary>The weight for which override position has an effect on the constrained Transform. This is a value in between 0 and 1.</summary>
public FloatProperty positionWeight;
/// <summary>The weight for which override rotation has an effect on the constrained Transform. This is a value in between 0 and 1.</summary>
public FloatProperty rotationWeight;
/// <summary>Cache for static properties in the job.</summary>
public AnimationJobCache cache;
/// <inheritdoc />
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
AffineTransform overrideTx;
if (source.IsValid(stream))
{
source.GetLocalTRS(stream, out Vector3 srcLPos, out Quaternion srcLRot, out _);
var sourceLocalTx = new AffineTransform(srcLPos, srcLRot);
var sourceToSpaceRot = cache.Get<Quaternion>(sourceToCurrSpaceRotIdx);
overrideTx = Quaternion.Inverse(sourceToSpaceRot) * (sourceInvLocalBindTx * sourceLocalTx) * sourceToSpaceRot;
}
else
overrideTx = new AffineTransform(position.Get(stream), Quaternion.Euler(rotation.Get(stream)));
Space overrideSpace = (Space)cache.GetRaw(spaceIdx);
var posW = positionWeight.Get(stream) * w;
var rotW = rotationWeight.Get(stream) * w;
switch (overrideSpace)
{
case Space.World:
{
driven.GetGlobalTR(stream, out Vector3 drivenWPos, out Quaternion drivenWRot);
driven.SetGlobalTR(
stream,
Vector3.Lerp(drivenWPos, overrideTx.translation, posW),
Quaternion.Lerp(drivenWRot, overrideTx.rotation, rotW)
);
}
break;
case Space.Local:
{
driven.GetLocalTRS(stream, out Vector3 drivenLPos, out Quaternion drivenLRot, out Vector3 drivenLScale);
driven.SetLocalTRS(
stream,
Vector3.Lerp(drivenLPos, overrideTx.translation, posW),
Quaternion.Lerp(drivenLRot, overrideTx.rotation, rotW),
drivenLScale
);
}
break;
case Space.Pivot:
{
driven.GetLocalTRS(stream, out Vector3 drivenLPos, out Quaternion drivenLRot, out Vector3 drivenLScale);
var drivenLocalTx = new AffineTransform(drivenLPos, drivenLRot);
overrideTx = drivenLocalTx * overrideTx;
driven.SetLocalTRS(
stream,
Vector3.Lerp(drivenLocalTx.translation, overrideTx.translation, posW),
Quaternion.Lerp(drivenLocalTx.rotation, overrideTx.rotation, rotW),
drivenLScale
);
}
break;
default:
break;
}
}
else
AnimationRuntimeUtils.PassThrough(stream, driven);
}
internal void UpdateSpace(int space)
{
if ((int)cache.GetRaw(spaceIdx) == space)
return;
cache.SetRaw(space, spaceIdx);
Space currSpace = (Space)space;
if (currSpace == Space.Pivot)
cache.Set(sourceToPivotRot, sourceToCurrSpaceRotIdx);
else if (currSpace == Space.Local)
cache.Set(sourceToLocalRot, sourceToCurrSpaceRotIdx);
else
cache.Set(sourceToWorldRot, sourceToCurrSpaceRotIdx);
}
}
/// <summary>
/// This interface defines the data mapping for OverrideTransform.
/// </summary>
public interface IOverrideTransformData
{
/// <summary>The Transform affected by the constraint source Transform.</summary>
Transform constrainedObject { get; }
/// <summary>The override source Transform.</summary>
Transform sourceObject { get; }
/// <summary>The override space.</summary>
int space { get; }
/// <summary>The path to the position weight property in the constraint component.</summary>
string positionWeightFloatProperty { get; }
/// <summary>The path to the rotation weight property in the constraint component.</summary>
string rotationWeightFloatProperty { get; }
/// <summary>The path to the override position property in the constraint component.</summary>
string positionVector3Property { get; }
/// <summary>The path to the override rotation property in the constraint component.</summary>
string rotationVector3Property { get; }
}
/// <summary>
/// The OverrideTransform job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class OverrideTransformJobBinder<T> : AnimationJobBinder<OverrideTransformJob, T>
where T : struct, IAnimationJobData, IOverrideTransformData
{
/// <inheritdoc />
public override OverrideTransformJob Create(Animator animator, ref T data, Component component)
{
var job = new OverrideTransformJob();
var cacheBuilder = new AnimationJobCacheBuilder();
job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject);
if (data.sourceObject != null)
{
// Cache source to possible space rotation offsets (world, local and pivot)
// at bind time so we can switch dynamically between them at runtime.
job.source = ReadOnlyTransformHandle.Bind(animator, data.sourceObject);
var sourceLocalTx = new AffineTransform(data.sourceObject.localPosition, data.sourceObject.localRotation);
job.sourceInvLocalBindTx = sourceLocalTx.Inverse();
var sourceWorldTx = new AffineTransform(data.sourceObject.position, data.sourceObject.rotation);
var drivenWorldTx = new AffineTransform(data.constrainedObject.position, data.constrainedObject.rotation);
job.sourceToWorldRot = sourceWorldTx.Inverse().rotation;
job.sourceToPivotRot = sourceWorldTx.InverseMul(drivenWorldTx).rotation;
var drivenParent = data.constrainedObject.parent;
if (drivenParent != null)
{
var drivenParentWorldTx = new AffineTransform(drivenParent.position, drivenParent.rotation);
job.sourceToLocalRot = sourceWorldTx.InverseMul(drivenParentWorldTx).rotation;
}
else
job.sourceToLocalRot = job.sourceToPivotRot;
}
job.spaceIdx = cacheBuilder.Add(data.space);
if (data.space == (int)OverrideTransformJob.Space.Pivot)
job.sourceToCurrSpaceRotIdx = cacheBuilder.Add(job.sourceToPivotRot);
else if (data.space == (int)OverrideTransformJob.Space.Local)
job.sourceToCurrSpaceRotIdx = cacheBuilder.Add(job.sourceToLocalRot);
else
job.sourceToCurrSpaceRotIdx = cacheBuilder.Add(job.sourceToWorldRot);
job.position = Vector3Property.Bind(animator, component, data.positionVector3Property);
job.rotation = Vector3Property.Bind(animator, component, data.rotationVector3Property);
job.positionWeight = FloatProperty.Bind(animator, component, data.positionWeightFloatProperty);
job.rotationWeight = FloatProperty.Bind(animator, component, data.rotationWeightFloatProperty);
job.cache = cacheBuilder.Build();
return job;
}
/// <inheritdoc />
public override void Destroy(OverrideTransformJob job)
{
job.cache.Dispose();
}
/// <inheritdoc />
public override void Update(OverrideTransformJob job, ref T data)
{
job.UpdateSpace(data.space);
}
}
}

View File

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

View File

@@ -0,0 +1,250 @@
using Unity.Collections;
namespace UnityEngine.Animations.Rigging
{
using TransformSyncer = RigSyncSceneToStreamJob.TransformSyncer;
using PropertySyncer = RigSyncSceneToStreamJob.PropertySyncer;
[Unity.Burst.BurstCompile]
internal struct RigSyncSceneToStreamJob : IAnimationJob
{
public struct TransformSyncer : System.IDisposable
{
public NativeArray<TransformSceneHandle> sceneHandles;
public NativeArray<TransformStreamHandle> streamHandles;
public static TransformSyncer Create(int size)
{
return new TransformSyncer() {
sceneHandles = new NativeArray<TransformSceneHandle>(size, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
streamHandles = new NativeArray<TransformStreamHandle>(size, Allocator.Persistent, NativeArrayOptions.UninitializedMemory)
};
}
public void Dispose()
{
if (sceneHandles.IsCreated)
sceneHandles.Dispose();
if (streamHandles.IsCreated)
streamHandles.Dispose();
}
public void BindAt(int index, Animator animator, Transform transform)
{
sceneHandles[index] = animator.BindSceneTransform(transform);
streamHandles[index] = animator.BindStreamTransform(transform);
}
public void Sync(ref AnimationStream stream)
{
for (int i = 0, count = sceneHandles.Length; i < count; ++i)
{
var sceneHandle = sceneHandles[i];
if (!sceneHandle.IsValid(stream))
continue;
var streamHandle = streamHandles[i];
sceneHandle.GetLocalTRS(stream, out Vector3 scenePos, out Quaternion sceneRot, out Vector3 sceneScale);
streamHandle.SetLocalTRS(stream, scenePos, sceneRot, sceneScale, true);
streamHandles[i] = streamHandle;
sceneHandles[i] = sceneHandle;
}
}
}
internal struct PropertySyncer : System.IDisposable
{
public NativeArray<PropertySceneHandle> sceneHandles;
public NativeArray<PropertyStreamHandle> streamHandles;
public NativeArray<float> buffer;
public static PropertySyncer Create(int size)
{
return new PropertySyncer() {
sceneHandles = new NativeArray<PropertySceneHandle>(size, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
streamHandles = new NativeArray<PropertyStreamHandle>(size, Allocator.Persistent, NativeArrayOptions.UninitializedMemory),
buffer = new NativeArray<float>(size, Allocator.Persistent, NativeArrayOptions.UninitializedMemory)
};
}
public void Dispose()
{
if (sceneHandles.IsCreated)
sceneHandles.Dispose();
if (streamHandles.IsCreated)
streamHandles.Dispose();
if (buffer.IsCreated)
buffer.Dispose();
}
public void BindAt(int index, Animator animator, Component component, string property)
{
sceneHandles[index] = animator.BindSceneProperty(component.transform, component.GetType(), property);
streamHandles[index] = animator.BindStreamProperty(component.transform, component.GetType(), property);
}
public void Sync(ref AnimationStream stream)
{
AnimationSceneHandleUtility.ReadFloats(stream, sceneHandles, buffer);
AnimationStreamHandleUtility.WriteFloats(stream, streamHandles, buffer, true);
}
public NativeArray<float> StreamValues(ref AnimationStream stream)
{
AnimationStreamHandleUtility.ReadFloats(stream, streamHandles, buffer);
return buffer;
}
}
public TransformSyncer transformSyncer;
public PropertySyncer propertySyncer;
public PropertySyncer rigWeightSyncer;
public PropertySyncer constraintWeightSyncer;
public NativeArray<float> rigStates;
public NativeArray<int> rigConstraintEndIdx;
public NativeArray<PropertyStreamHandle> modulatedConstraintWeights;
public void ProcessRootMotion(AnimationStream stream) { }
public void ProcessAnimation(AnimationStream stream)
{
transformSyncer.Sync(ref stream);
propertySyncer.Sync(ref stream);
rigWeightSyncer.Sync(ref stream);
constraintWeightSyncer.Sync(ref stream);
var currRigWeights = rigWeightSyncer.StreamValues(ref stream);
var currConstraintWeights = constraintWeightSyncer.StreamValues(ref stream);
int rigIndex = 0;
for (int i = 0, count = currConstraintWeights.Length; i < count; ++i)
{
if (i >= rigConstraintEndIdx[rigIndex])
rigIndex++;
currConstraintWeights[i] *= (currRigWeights[rigIndex] * rigStates[rigIndex]);
}
AnimationStreamHandleUtility.WriteFloats(stream, modulatedConstraintWeights, currConstraintWeights, false);
}
}
internal struct SyncableProperties
{
public RigProperties rig;
public ConstraintProperties[] constraints;
}
internal interface IRigSyncSceneToStreamData
{
Transform[] syncableTransforms { get; }
SyncableProperties[] syncableProperties { get; }
bool[] rigStates { get; }
}
internal class RigSyncSceneToStreamJobBinder<T> : AnimationJobBinder<RigSyncSceneToStreamJob, T>
where T : struct, IAnimationJobData, IRigSyncSceneToStreamData
{
internal static string[] s_PropertyElementNames = new string[] {".x", ".y", ".z", ".w"};
public override RigSyncSceneToStreamJob Create(Animator animator, ref T data, Component component)
{
var job = new RigSyncSceneToStreamJob();
var transforms = data.syncableTransforms;
if (transforms != null)
{
job.transformSyncer = TransformSyncer.Create(transforms.Length);
for (int i = 0; i < transforms.Length; ++i)
job.transformSyncer.BindAt(i, animator, transforms[i]);
}
var properties = data.syncableProperties;
if (properties != null)
{
int rigCount = properties.Length, constraintCount = 0, propertyCount = 0;
for (int i = 0; i < properties.Length; ++i)
{
constraintCount += properties[i].constraints.Length;
for (int j = 0; j < properties[i].constraints.Length; ++j)
for (int k = 0; k < properties[i].constraints[j].properties.Length; ++k)
propertyCount += properties[i].constraints[j].properties[k].descriptor.size;
}
job.propertySyncer = PropertySyncer.Create(propertyCount);
job.rigWeightSyncer = PropertySyncer.Create(rigCount);
job.constraintWeightSyncer = PropertySyncer.Create(constraintCount);
job.rigStates = new NativeArray<float>(rigCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.rigConstraintEndIdx = new NativeArray<int>(rigCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.modulatedConstraintWeights = new NativeArray<PropertyStreamHandle>(constraintCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
int constraintIdx = 0, propertyIdx = 0;
for (int i = 0; i < properties.Length; ++i)
{
job.rigWeightSyncer.BindAt(i, animator, properties[i].rig.component, RigProperties.s_Weight);
job.rigStates[i] = data.rigStates[i] ? 1f : 0f;
var constraints = properties[i].constraints;
for (int j = 0; j < constraints.Length; ++j)
{
ref var constraint = ref constraints[j];
job.constraintWeightSyncer.BindAt(constraintIdx, animator, constraint.component, ConstraintProperties.s_Weight);
job.modulatedConstraintWeights[constraintIdx++] = animator.BindCustomStreamProperty(
ConstraintsUtils.ConstructCustomPropertyName(constraint.component, ConstraintProperties.s_Weight),
CustomStreamPropertyType.Float
);
for (int k = 0; k < constraint.properties.Length; ++k)
{
ref var property = ref constraint.properties[k];
if (property.descriptor.size == 1)
job.propertySyncer.BindAt(propertyIdx++, animator, constraint.component, property.name);
else
{
Debug.Assert(property.descriptor.size <= 4);
for (int l = 0; l < property.descriptor.size; ++l)
job.propertySyncer.BindAt(propertyIdx++, animator, constraint.component, property.name + s_PropertyElementNames[l]);
}
}
}
job.rigConstraintEndIdx[i] = constraintIdx;
}
}
return job;
}
public override void Destroy(RigSyncSceneToStreamJob job)
{
job.transformSyncer.Dispose();
job.propertySyncer.Dispose();
job.rigWeightSyncer.Dispose();
job.constraintWeightSyncer.Dispose();
if (job.rigStates.IsCreated)
job.rigStates.Dispose();
if (job.rigConstraintEndIdx.IsCreated)
job.rigConstraintEndIdx.Dispose();
if (job.modulatedConstraintWeights.IsCreated)
job.modulatedConstraintWeights.Dispose();
}
public override void Update(RigSyncSceneToStreamJob job, ref T data)
{
int count = Mathf.Min(job.rigStates.Length, data.rigStates.Length);
for (int i = 0; i < count; ++i)
job.rigStates[i] = data.rigStates[i] ? 1f : 0f;
}
}
}

View File

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

View File

@@ -0,0 +1,312 @@
using System;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// Read/write handle on a Transform component used in Animation C# Jobs.
/// </summary>
public struct ReadWriteTransformHandle
{
TransformStreamHandle m_Handle;
/// <summary>
/// Gets the position of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The position of the transform relative to the parent.</returns>
public Vector3 GetLocalPosition(AnimationStream stream) => m_Handle.GetLocalPosition(stream);
/// <summary>
/// Gets the rotation of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The rotation of the transform relative to the parent.</returns>
public Quaternion GetLocalRotation(AnimationStream stream) => m_Handle.GetLocalRotation(stream);
/// <summary>
/// Gets the scale of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The scale of the transform relative to the parent.</returns>
public Vector3 GetLocalScale(AnimationStream stream) => m_Handle.GetLocalScale(stream);
/// <summary>
/// Gets the position, rotation and scale of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="position">The position of the transform relative to the parent.</param>
/// <param name="rotation">The rotation of the transform relative to the parent.</param>
/// <param name="scale">The scale of the transform relative to the parent.</param>
public void GetLocalTRS(AnimationStream stream, out Vector3 position, out Quaternion rotation, out Vector3 scale) =>
m_Handle.GetLocalTRS(stream, out position, out rotation, out scale);
/// <summary>
/// Sets the position of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="position">The position of the transform relative to the parent.</param>
public void SetLocalPosition(AnimationStream stream, Vector3 position) => m_Handle.SetLocalPosition(stream, position);
/// <summary>
/// Sets the rotation of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="rotation">The rotation of the transform relative to the parent.</param>
public void SetLocalRotation(AnimationStream stream, Quaternion rotation) => m_Handle.SetLocalRotation(stream, rotation);
/// <summary>
/// Sets the scale of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="scale">The scale of the transform relative to the parent.</param>
public void SetLocalScale(AnimationStream stream, Vector3 scale) => m_Handle.SetLocalScale(stream, scale);
/// <summary>
/// Sets the position, rotation and scale of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="position">The position of the transform relative to the parent.</param>
/// <param name="rotation">The rotation of the transform relative to the parent.</param>
/// <param name="scale">The scale of the transform relative to the parent.</param>
/// <param name="useMask">Set to true to write the specified parameters if the matching stream parameters have not already been modified.</param>
public void SetLocalTRS(AnimationStream stream, Vector3 position, Quaternion rotation, Vector3 scale, bool useMask = false) =>
m_Handle.SetLocalTRS(stream, position, rotation, scale, useMask);
/// <summary>
/// Gets the position of the transform in world space.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The position of the transform in world space.</returns>
public Vector3 GetPosition(AnimationStream stream) => m_Handle.GetPosition(stream);
/// <summary>
/// Gets the rotation of the transform in world space.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The rotation of the transform in world space.</returns>
public Quaternion GetRotation(AnimationStream stream) => m_Handle.GetRotation(stream);
/// <summary>
/// Gets the position and scaled rotation of the transform in world space.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="position">The position of the transform in world space.</param>
/// <param name="rotation">The rotation of the transform in world space.</param>
public void GetGlobalTR(AnimationStream stream, out Vector3 position, out Quaternion rotation) =>
m_Handle.GetGlobalTR(stream, out position, out rotation);
/// <summary>
/// Sets the position of the transform in world space.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="position">The position of the transform in world space.</param>
public void SetPosition(AnimationStream stream, Vector3 position) => m_Handle.SetPosition(stream, position);
/// <summary>
/// Sets the rotation of the transform in world space.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="rotation"> The rotation of the transform in world space.</param>
public void SetRotation(AnimationStream stream, Quaternion rotation) => m_Handle.SetRotation(stream, rotation);
/// <summary>
/// Sets the position and rotation of the transform in world space.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="position">The position of the transform in world space.</param>
/// <param name="rotation">The rotation of the transform in world space.</param>
/// <param name="useMask">Set to true to write the specified parameters if the matching stream parameters have not already been modified.</param>
public void SetGlobalTR(AnimationStream stream, Vector3 position, Quaternion rotation, bool useMask = false) =>
m_Handle.SetGlobalTR(stream, position, rotation, useMask);
/// <summary>
/// Returns whether this handle is resolved.
/// A ReadWriteTransformHandle is resolved if it is valid, if it has the same bindings version than the one in the stream, and if it is bound to the transform in the stream.
/// A ReadWriteTransformHandle can become unresolved if the animator bindings have changed or if the transform had been destroyed.
/// </summary>
/// <seealso cref="ReadWriteTransformHandle.Resolve"/>
/// <seealso cref="ReadWriteTransformHandle.IsValid"/>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>Returns true if the handle is resolved, false otherwise.</returns>
public bool IsResolved(AnimationStream stream) => m_Handle.IsResolved(stream);
/// <summary>
/// Returns whether this is a valid handle.
/// A ReadWriteTransformHandle may be invalid if, for example, you didn't use the correct function to create it.
/// </summary>
/// <seealso cref="ReadWriteTransformHandle.Bind"/>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>Returns whether this is a valid handle.</returns>
public bool IsValid(AnimationStream stream) => m_Handle.IsValid(stream);
/// <summary>
/// Bind this handle with an animated values from the AnimationStream.
/// Handles are lazily resolved as they're accessed, but in order to prevent unwanted CPU spikes, this method allows to resolve handles in a deterministic way.
/// </summary>
/// <seealso cref="ReadWriteTransformHandle.IsResolved"/>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
public void Resolve(AnimationStream stream) => m_Handle.Resolve(stream);
/// <summary>
/// Create a ReadWriteTransformHandle representing the new binding between the Animator and a Transform already bound to the Animator.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="transform">The Transform to bind.</param>
/// <returns>Returns the ReadWriteTransformHandle that represents the new binding.</returns>
/// <exception cref="ArgumentNullException">Thrown if transform is null.</exception>
/// <exception cref="InvalidOperationException">Thrown if transform is not a child in the Animator hierarchy.</exception>
public static ReadWriteTransformHandle Bind(Animator animator, Transform transform)
{
ReadWriteTransformHandle handle = new ReadWriteTransformHandle();
if (transform == null)
throw new ArgumentNullException(nameof(transform));
if (!transform.IsChildOf(animator.avatarRoot))
throw new InvalidOperationException($"Transform '{transform.name}' is not a child of the Animator hierarchy, and cannot be written to.");
handle.m_Handle = animator.BindStreamTransform(transform);
return handle;
}
}
/// <summary>
/// Read-only handle on a Transform component used in Animation C# Jobs.
/// </summary>
public struct ReadOnlyTransformHandle
{
TransformStreamHandle m_StreamHandle;
TransformSceneHandle m_SceneHandle;
byte m_InStream;
/// <summary>
/// Gets the position of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The position of the transform relative to the parent.</returns>
public Vector3 GetLocalPosition(AnimationStream stream) =>
m_InStream == 1 ? m_StreamHandle.GetLocalPosition(stream) : m_SceneHandle.GetLocalPosition(stream);
/// <summary>
/// Gets the rotation of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The rotation of the transform relative to the parent.</returns>
public Quaternion GetLocalRotation(AnimationStream stream) =>
m_InStream == 1 ? m_StreamHandle.GetLocalRotation(stream) : m_SceneHandle.GetLocalRotation(stream);
/// <summary>
/// Gets the scale of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The scale of the transform relative to the parent.</returns>
public Vector3 GetLocalScale(AnimationStream stream) =>
m_InStream == 1 ? m_StreamHandle.GetLocalScale(stream) : m_SceneHandle.GetLocalScale(stream);
/// <summary>
/// Gets the position, rotation and scale of the transform relative to the parent.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="position">The position of the transform relative to the parent.</param>
/// <param name="rotation">The rotation of the transform relative to the parent.</param>
/// <param name="scale">The scale of the transform relative to the parent.</param>
public void GetLocalTRS(AnimationStream stream, out Vector3 position, out Quaternion rotation, out Vector3 scale)
{
if (m_InStream == 1)
m_StreamHandle.GetLocalTRS(stream, out position, out rotation, out scale);
else
m_SceneHandle.GetLocalTRS(stream, out position, out rotation, out scale);
}
/// <summary>
/// Gets the matrix of the transform in local space.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The matrix of the transform in local space.</returns>
public Matrix4x4 GetLocalToParentMatrix(AnimationStream stream) =>
m_InStream == 1 ? m_StreamHandle.GetLocalToParentMatrix(stream) : m_SceneHandle.GetLocalToParentMatrix(stream);
/// <summary>
/// Gets the position of the transform in world space.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The position of the transform in world space.</returns>
public Vector3 GetPosition(AnimationStream stream) =>
m_InStream == 1 ? m_StreamHandle.GetPosition(stream) : m_SceneHandle.GetPosition(stream);
/// <summary>
/// Gets the rotation of the transform in world space.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The rotation of the transform in world space.</returns>
public Quaternion GetRotation(AnimationStream stream) =>
m_InStream == 1 ? m_StreamHandle.GetRotation(stream) : m_SceneHandle.GetRotation(stream);
/// <summary>
/// Gets the position and scaled rotation of the transform in world space.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <param name="position">The position of the transform in world space.</param>
/// <param name="rotation">The rotation of the transform in world space.</param>
public void GetGlobalTR(AnimationStream stream, out Vector3 position, out Quaternion rotation)
{
if (m_InStream == 1)
m_StreamHandle.GetGlobalTR(stream, out position, out rotation);
else
m_SceneHandle.GetGlobalTR(stream, out position, out rotation);
}
/// <summary>
/// Gets the matrix of the transform in world space.
/// </summary>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>The matrix of the transform in world space.</returns>
public Matrix4x4 GetLocalToWorldMatrix(AnimationStream stream) =>
m_InStream == 1 ? m_StreamHandle.GetLocalToWorldMatrix(stream) : m_SceneHandle.GetLocalToWorldMatrix(stream);
/// <summary>
/// Returns whether this handle is resolved.
/// A ReadOnlyTransformHandle is resolved if it is valid, if it has the same bindings version than the one in the stream, and if it is bound to the transform in the stream.
/// A ReadOnlyTransformHandle can become unresolved if the animator bindings have changed or if the transform had been destroyed.
/// </summary>
/// <seealso cref="ReadWriteTransformHandle.Resolve"/>
/// <seealso cref="ReadWriteTransformHandle.IsValid"/>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>Returns true if the handle is resolved, false otherwise.</returns>
public bool IsResolved(AnimationStream stream) =>
m_InStream == 1 ? m_StreamHandle.IsResolved(stream) : true;
/// <summary>
/// Returns whether this is a valid handle.
/// A ReadOnlyTransformHandle may be invalid if, for example, you didn't use the correct function to create it.
/// </summary>
/// <seealso cref="ReadWriteTransformHandle.Bind"/>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
/// <returns>Returns whether this is a valid handle.</returns>
public bool IsValid(AnimationStream stream) =>
m_InStream == 1 ? m_StreamHandle.IsValid(stream) : m_SceneHandle.IsValid(stream);
/// <summary>
/// Bind this handle with an animated values from the AnimationStream.
/// Handles are lazily resolved as they're accessed, but in order to prevent unwanted CPU spikes, this method allows to resolve handles in a deterministic way.
/// </summary>
/// <seealso cref="ReadWriteTransformHandle.IsResolved"/>
/// <param name="stream">The AnimationStream that holds the animated values.</param>
public void Resolve(AnimationStream stream)
{
if (m_InStream == 1)
m_StreamHandle.Resolve(stream);
}
/// <summary>
/// Create a ReadOnlyTransformHandle representing the new binding between the Animator and a Transform already bound to the Animator.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="transform">The Transform to bind.</param>
/// <returns>Returns the ReadOnlyTransformHandle that represents the new binding.</returns>
/// <exception cref="ArgumentNullException">Thrown if transform is null.</exception>
public static ReadOnlyTransformHandle Bind(Animator animator, Transform transform)
{
ReadOnlyTransformHandle handle = new ReadOnlyTransformHandle();
if (transform == null)
throw new ArgumentNullException(nameof(transform));
handle.m_InStream = (byte)(transform.IsChildOf(animator.avatarRoot) ? 1 : 0);
if (handle.m_InStream == 1)
handle.m_StreamHandle = animator.BindStreamTransform(transform);
else
handle.m_SceneHandle = animator.BindSceneTransform(transform);
return handle;
}
}
}

View File

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

View File

@@ -0,0 +1,155 @@
using Unity.Collections;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The TwistChain constraint job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct TwistChainConstraintJob : IWeightedAnimationJob
{
/// <summary>The Transform handle for the root target Transform.</summary>
public ReadWriteTransformHandle rootTarget;
/// <summary>The Transform handle for the tip target Transform.</summary>
public ReadWriteTransformHandle tipTarget;
/// <summary>An array of Transform handles that represents the Transform chain.</summary>
public NativeArray<ReadWriteTransformHandle> chain;
/// <summary>An array of interpolant values used to reevaluate the weights.</summary>
public NativeArray<float> steps;
/// <summary>An array of weight values used to adjust how twist is distributed along the chain.</summary>
public NativeArray<float> weights;
/// <summary>An array of rotation offsets to maintain the chain initial shape.</summary>
public NativeArray<Quaternion> rotations;
/// <inheritdoc />
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
// Retrieve root and tip rotation.
Quaternion rootRotation = rootTarget.GetRotation(stream);
Quaternion tipRotation = tipTarget.GetRotation(stream);
// Interpolate rotation on chain.
chain[0].SetRotation(stream, Quaternion.Lerp(chain[0].GetRotation(stream), rootRotation, w));
for (int i = 1; i < chain.Length - 1; ++i)
{
chain[i].SetRotation(stream, Quaternion.Lerp(chain[i].GetRotation(stream), rotations[i] * Quaternion.Lerp(rootRotation, tipRotation, weights[i]), w));
}
chain[chain.Length - 1].SetRotation(stream, Quaternion.Lerp(chain[chain.Length - 1].GetRotation(stream), tipRotation, w));
#if UNITY_EDITOR
// Update position of tip handle for easier visualization.
rootTarget.SetPosition(stream, chain[0].GetPosition(stream));
tipTarget.SetPosition(stream, chain[chain.Length - 1].GetPosition(stream));
#endif
}
else
{
for (int i = 0; i < chain.Length; ++i)
AnimationRuntimeUtils.PassThrough(stream, chain[i]);
}
}
}
/// <summary>
/// This interface defines the data mapping for the TwistChain constraint.
/// </summary>
public interface ITwistChainConstraintData
{
/// <summary>The root Transform of the TwistChain hierarchy.</summary>
Transform root { get; }
/// <summary>The tip Transform of the TwistChain hierarchy.</summary>
Transform tip { get; }
/// <summary>The TwistChain root target Transform.</summary>
Transform rootTarget { get; }
/// <summary>The TwistChain tip target Transform.</summary>
Transform tipTarget { get; }
/// <summary>Curve with weight values used to adjust how twist is distributed along the chain.</summary>
AnimationCurve curve { get; }
}
/// <summary>
/// The TwistChain constraint job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class TwistChainConstraintJobBinder<T> : AnimationJobBinder<TwistChainConstraintJob, T>
where T : struct, IAnimationJobData, ITwistChainConstraintData
{
/// <inheritdoc />
public override TwistChainConstraintJob Create(Animator animator, ref T data, Component component)
{
// Retrieve chain in-between root and tip transforms.
Transform[] chain = ConstraintsUtils.ExtractChain(data.root, data.tip);
// Extract steps from chain.
float[] steps = ConstraintsUtils.ExtractSteps(chain);
// Build Job.
var job = new TwistChainConstraintJob();
job.chain = new NativeArray<ReadWriteTransformHandle>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.steps = new NativeArray<float>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.weights = new NativeArray<float>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.rotations = new NativeArray<Quaternion>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.rootTarget = ReadWriteTransformHandle.Bind(animator, data.rootTarget);
job.tipTarget = ReadWriteTransformHandle.Bind(animator, data.tipTarget);
// Set values in NativeArray.
for (int i = 0; i < chain.Length; ++i)
{
job.chain[i] = ReadWriteTransformHandle.Bind(animator, chain[i]);
job.steps[i] = steps[i];
job.weights[i] = Mathf.Clamp01(data.curve.Evaluate(steps[i]));
}
job.rotations[0] = Quaternion.identity;
job.rotations[chain.Length - 1] = Quaternion.identity;
for (int i = 1; i < chain.Length - 1; ++i)
{
job.rotations[i] = Quaternion.Inverse(Quaternion.Lerp(chain[0].rotation, chain[chain.Length - 1].rotation, job.weights[i])) * chain[i].rotation;
}
return job;
}
/// <inheritdoc />
public override void Destroy(TwistChainConstraintJob job)
{
job.chain.Dispose();
job.weights.Dispose();
job.steps.Dispose();
job.rotations.Dispose();
}
#if UNITY_EDITOR
/// <inheritdoc />
public override void Update(TwistChainConstraintJob job, ref T data)
{
// Update weights based on curve.
for (int i = 0; i < job.steps.Length; ++i)
{
job.weights[i] = Mathf.Clamp01(data.curve.Evaluate(job.steps[i]));
}
}
#endif
}
}

View File

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

View File

@@ -0,0 +1,141 @@
using Unity.Collections;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The TwistCorrection job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct TwistCorrectionJob : IWeightedAnimationJob
{
/// <summary>The Transform handle for the source object Transform.</summary>
public ReadOnlyTransformHandle source;
/// <summary>Cached inverse local rotation for source Transform.</summary>
public Quaternion sourceInverseBindRotation;
/// <summary>The local twist axis</summary>
public Vector3 axisMask;
/// <summary>List of Transform handles for the twist nodes.</summary>
public NativeArray<ReadWriteTransformHandle> twistTransforms;
/// <summary>List of weights for the twist nodes.</summary>
public NativeArray<PropertyStreamHandle> twistWeights;
/// <summary>List of cached local rotation for twist nodes.</summary>
public NativeArray<Quaternion> twistBindRotations;
/// <summary>Buffer used to store weights during job execution.</summary>
public NativeArray<float> weightBuffer;
/// <inheritdoc />
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
if (twistTransforms.Length == 0)
return;
AnimationStreamHandleUtility.ReadFloats(stream, twistWeights, weightBuffer);
Quaternion twistRot = TwistRotation(axisMask, sourceInverseBindRotation * source.GetLocalRotation(stream));
Quaternion invTwistRot = Quaternion.Inverse(twistRot);
for (int i = 0; i < twistTransforms.Length; ++i)
{
ReadWriteTransformHandle twistTransform = twistTransforms[i];
float twistWeight = Mathf.Clamp(weightBuffer[i], -1f, 1f);
Quaternion rot = Quaternion.Lerp(Quaternion.identity, Mathf.Sign(twistWeight) < 0f ? invTwistRot : twistRot, Mathf.Abs(twistWeight));
twistTransform.SetLocalRotation(stream, Quaternion.Lerp(twistBindRotations[i], rot, w));
// Required to update handles with binding info.
twistTransforms[i] = twistTransform;
}
}
else
{
for (int i = 0; i < twistTransforms.Length; ++i)
AnimationRuntimeUtils.PassThrough(stream, twistTransforms[i]);
}
}
static Quaternion TwistRotation(Vector3 axis, Quaternion rot)
{
return new Quaternion(axis.x * rot.x, axis.y * rot.y, axis.z * rot.z, rot.w);
}
}
/// <summary>
/// This interface defines the data mapping for TwistCorrection.
/// </summary>
public interface ITwistCorrectionData
{
/// <summary>The source Transform that influences the twist nodes.</summary>
Transform source { get; }
/// <summary>
/// The list of Transforms on which to apply twist corrections.
/// Each twist node has a weight that ranges from -1 to 1 to control
/// how closely a twist node follows source rotation (from 0 to 1),
/// or opposite rotation (from -1 to 0).
/// </summary>
WeightedTransformArray twistNodes { get; }
/// <summary>The local twist axis of the source Transform on which to evaluate twist rotation.</summary>
Vector3 twistAxis { get; }
/// <summary>The path to the twist nodes property in the constraint component.</summary>
string twistNodesProperty { get; }
}
/// <summary>
/// The TwistCorrection job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class TwistCorrectionJobBinder<T> : AnimationJobBinder<TwistCorrectionJob, T>
where T : struct, IAnimationJobData, ITwistCorrectionData
{
/// <inheritdoc />
public override TwistCorrectionJob Create(Animator animator, ref T data, Component component)
{
var job = new TwistCorrectionJob();
job.source = ReadOnlyTransformHandle.Bind(animator, data.source);
job.sourceInverseBindRotation = Quaternion.Inverse(data.source.localRotation);
job.axisMask = data.twistAxis;
WeightedTransformArray twistNodes = data.twistNodes;
WeightedTransformArrayBinder.BindReadWriteTransforms(animator, component, twistNodes, out job.twistTransforms);
WeightedTransformArrayBinder.BindWeights(animator, component, twistNodes, data.twistNodesProperty, out job.twistWeights);
job.weightBuffer = new NativeArray<float>(twistNodes.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.twistBindRotations = new NativeArray<Quaternion>(twistNodes.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
for (int i = 0; i < twistNodes.Count; ++i)
{
var sourceTransform = twistNodes[i].transform;
job.twistBindRotations[i] = sourceTransform.localRotation;
}
return job;
}
/// <inheritdoc />
public override void Destroy(TwistCorrectionJob job)
{
job.twistTransforms.Dispose();
job.twistWeights.Dispose();
job.twistBindRotations.Dispose();
job.weightBuffer.Dispose();
}
}
}

View File

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

View File

@@ -0,0 +1,142 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The TwoBoneIK constraint job.
/// </summary>
[Unity.Burst.BurstCompile]
public struct TwoBoneIKConstraintJob : IWeightedAnimationJob
{
/// <summary>The transform handle for the root transform.</summary>
public ReadWriteTransformHandle root;
/// <summary>The transform handle for the mid transform.</summary>
public ReadWriteTransformHandle mid;
/// <summary>The transform handle for the tip transform.</summary>
public ReadWriteTransformHandle tip;
/// <summary>The transform handle for the hint transform.</summary>
public ReadOnlyTransformHandle hint;
/// <summary>The transform handle for the target transform.</summary>
public ReadOnlyTransformHandle target;
/// <summary>The offset applied to the target transform if maintainTargetPositionOffset or maintainTargetRotationOffset is enabled.</summary>
public AffineTransform targetOffset;
/// <summary>The weight for which target position has an effect on IK calculations. This is a value in between 0 and 1.</summary>
public FloatProperty targetPositionWeight;
/// <summary>The weight for which target rotation has an effect on IK calculations. This is a value in between 0 and 1.</summary>
public FloatProperty targetRotationWeight;
/// <summary>The weight for which hint transform has an effect on IK calculations. This is a value in between 0 and 1.</summary>
public FloatProperty hintWeight;
/// <summary>The main weight given to the constraint. This is a value in between 0 and 1.</summary>
public FloatProperty jobWeight { get; set; }
/// <summary>
/// Defines what to do when processing the root motion.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessRootMotion(AnimationStream stream) { }
/// <summary>
/// Defines what to do when processing the animation.
/// </summary>
/// <param name="stream">The animation stream to work on.</param>
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
AnimationRuntimeUtils.SolveTwoBoneIK(
stream, root, mid, tip, target, hint,
targetPositionWeight.Get(stream) * w,
targetRotationWeight.Get(stream) * w,
hintWeight.Get(stream) * w,
targetOffset
);
}
else
{
AnimationRuntimeUtils.PassThrough(stream, root);
AnimationRuntimeUtils.PassThrough(stream, mid);
AnimationRuntimeUtils.PassThrough(stream, tip);
}
}
}
/// <summary>
/// This interface defines the data mapping for the TwoBoneIK constraint.
/// </summary>
public interface ITwoBoneIKConstraintData
{
/// <summary>The root transform of the two bones hierarchy.</summary>
Transform root { get; }
/// <summary>The mid transform of the two bones hierarchy.</summary>
Transform mid { get; }
/// <summary>The tip transform of the two bones hierarchy.</summary>
Transform tip { get; }
/// <summary>The IK target transform.</summary>
Transform target { get; }
/// <summary>The IK hint transform.</summary>
Transform hint { get; }
/// <summary>This is used to maintain the offset of the tip position to the target position.</summary>
bool maintainTargetPositionOffset { get; }
/// <summary>This is used to maintain the offset of the tip rotation to the target rotation.</summary>
bool maintainTargetRotationOffset { get; }
/// <summary>The path to the target position weight property in the constraint component.</summary>
string targetPositionWeightFloatProperty { get; }
/// <summary>The path to the target rotation weight property in the constraint component.</summary>
string targetRotationWeightFloatProperty { get; }
/// <summary>The path to the hint weight property in the constraint component.</summary>
string hintWeightFloatProperty { get; }
}
/// <summary>
/// The TwoBoneIK constraint job binder.
/// </summary>
/// <typeparam name="T">The constraint data type</typeparam>
public class TwoBoneIKConstraintJobBinder<T> : AnimationJobBinder<TwoBoneIKConstraintJob, T>
where T : struct, IAnimationJobData, ITwoBoneIKConstraintData
{
/// <summary>
/// Creates the animation job.
/// </summary>
/// <param name="animator">The animated hierarchy Animator component.</param>
/// <param name="data">The constraint data.</param>
/// <param name="component">The constraint component.</param>
/// <returns>Returns a new job interface.</returns>
public override TwoBoneIKConstraintJob Create(Animator animator, ref T data, Component component)
{
var job = new TwoBoneIKConstraintJob();
job.root = ReadWriteTransformHandle.Bind(animator, data.root);
job.mid = ReadWriteTransformHandle.Bind(animator, data.mid);
job.tip = ReadWriteTransformHandle.Bind(animator, data.tip);
job.target = ReadOnlyTransformHandle.Bind(animator, data.target);
if (data.hint != null)
job.hint = ReadOnlyTransformHandle.Bind(animator, data.hint);
job.targetOffset = AffineTransform.identity;
if (data.maintainTargetPositionOffset)
job.targetOffset.translation = data.tip.position - data.target.position;
if (data.maintainTargetRotationOffset)
job.targetOffset.rotation = Quaternion.Inverse(data.target.rotation) * data.tip.rotation;
job.targetPositionWeight = FloatProperty.Bind(animator, component, data.targetPositionWeightFloatProperty);
job.targetRotationWeight = FloatProperty.Bind(animator, component, data.targetRotationWeightFloatProperty);
job.hintWeight = FloatProperty.Bind(animator, component, data.hintWeightFloatProperty);
return job;
}
/// <summary>
/// Destroys the animation job.
/// </summary>
/// <param name="job">The animation job to destroy.</param>
public override void Destroy(TwoBoneIKConstraintJob job)
{
}
}
}

View File

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

View File

@@ -0,0 +1,62 @@
using Unity.Collections;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// This class is used to create Animation C# jobs handles for WeightedTransformArray.
/// </summary>
public class WeightedTransformArrayBinder
{
/// <summary>
/// Creates an array of ReadOnlyTransformHandles representing the new bindings between the Animator and the Transforms in a WeightedTransformArray.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="component">The component owning the WeightedTransformArray property.</param>
/// <param name="weightedTransformArray">The WeightedTransformArray property.</param>
/// <param name="transforms">The resulting array of ReadOnlyTransformHandles.</param>
public static void BindReadOnlyTransforms(Animator animator, Component component, WeightedTransformArray weightedTransformArray, out NativeArray<ReadOnlyTransformHandle> transforms)
{
transforms = new NativeArray<ReadOnlyTransformHandle>(weightedTransformArray.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
for (int index = 0; index < weightedTransformArray.Count; ++index)
{
transforms[index] = ReadOnlyTransformHandle.Bind(animator, weightedTransformArray[index].transform);
}
}
/// <summary>
/// Creates an array of ReadWriteTransformHandles representing the new bindings between the Animator and the Transforms in a WeightedTransformArray.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="component">The component owning the WeightedTransformArray property.</param>
/// <param name="weightedTransformArray">The WeightedTransformArray property.</param>
/// <param name="transforms">The resulting array of ReadWriteTransformHandles.</param>
public static void BindReadWriteTransforms(Animator animator, Component component, WeightedTransformArray weightedTransformArray, out NativeArray<ReadWriteTransformHandle> transforms)
{
transforms = new NativeArray<ReadWriteTransformHandle>(weightedTransformArray.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
for (int index = 0; index < weightedTransformArray.Count; ++index)
{
transforms[index] = ReadWriteTransformHandle.Bind(animator, weightedTransformArray[index].transform);
}
}
/// <summary>
/// Creates an array of PropertyStreamHandle representing the new bindings between the Animator and the weights in a WeightedTransformArray.
/// </summary>
/// <param name="animator">The Animator on which to bind the new handle.</param>
/// <param name="component">The component owning the WeightedTransformArray property.</param>
/// <param name="weightedTransformArray">The WeightedTransformArray property.</param>
/// <param name="name"></param>
/// <param name="weights"></param>
public static void BindWeights(Animator animator, Component component, WeightedTransformArray weightedTransformArray, string name, out NativeArray<PropertyStreamHandle> weights)
{
weights = new NativeArray<PropertyStreamHandle>(weightedTransformArray.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
for (int index = 0; index < weightedTransformArray.Count; ++index)
{
weights[index] = animator.BindStreamProperty(component.transform, component.GetType(), name + ".m_Item" + index + ".weight");
}
}
}
}

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8e51642a8e5961844a4f89eccdc5eccf
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 57fb05f5d7fd88b41b5eca2077a707f3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,92 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The Blend constraint data.
/// </summary>
[System.Serializable]
public struct BlendConstraintData : IAnimationJobData, IBlendConstraintData
{
[SerializeField] Transform m_ConstrainedObject;
[SyncSceneToStream, SerializeField] Transform m_SourceA;
[SyncSceneToStream, SerializeField] Transform m_SourceB;
[SyncSceneToStream, SerializeField] bool m_BlendPosition;
[SyncSceneToStream, SerializeField] bool m_BlendRotation;
[SyncSceneToStream, SerializeField, Range(0f, 1f)] float m_PositionWeight;
[SyncSceneToStream, SerializeField, Range(0f, 1f)] float m_RotationWeight;
[NotKeyable, SerializeField] bool m_MaintainPositionOffsets;
[NotKeyable, SerializeField] bool m_MaintainRotationOffsets;
/// <inheritdoc />
public Transform constrainedObject { get => m_ConstrainedObject; set => m_ConstrainedObject = value; }
/// <inheritdoc />
public Transform sourceObjectA { get => m_SourceA; set => m_SourceA = value; }
/// <inheritdoc />
public Transform sourceObjectB { get => m_SourceB; set => m_SourceB = value; }
/// <summary>Toggles whether position is blended in the constraint.</summary>
public bool blendPosition { get => m_BlendPosition; set => m_BlendPosition = value; }
/// <summary>Toggles whether rotation is blended in the constraint.</summary>
public bool blendRotation { get => m_BlendRotation; set => m_BlendRotation = value; }
/// <summary>
/// Specifies the weight with which to blend position.
/// A weight of zero will result in the position of sourceObjectA, while a weight of one will result in the position of sourceObjectB.
/// </summary>
public float positionWeight { get => m_PositionWeight; set => m_PositionWeight = Mathf.Clamp01(value); }
/// <summary>
/// Specifies the weight with which to blend rotation.
/// A weight of zero will result in the rotation of sourceObjectA, while a weight of one will result in the rotation of sourceObjectB.
/// </summary>
public float rotationWeight { get => m_RotationWeight; set => m_RotationWeight = Mathf.Clamp01(value); }
/// <inheritdoc />
public bool maintainPositionOffsets { get => m_MaintainPositionOffsets; set => m_MaintainPositionOffsets = value; }
/// <inheritdoc />
public bool maintainRotationOffsets { get => m_MaintainRotationOffsets; set => m_MaintainRotationOffsets = value; }
/// <inheritdoc />
string IBlendConstraintData.blendPositionBoolProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_BlendPosition));
/// <inheritdoc />
string IBlendConstraintData.blendRotationBoolProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_BlendRotation));
/// <inheritdoc />
string IBlendConstraintData.positionWeightFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_PositionWeight));
/// <inheritdoc />
string IBlendConstraintData.rotationWeightFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_RotationWeight));
/// <inheritdoc />
bool IAnimationJobData.IsValid() => !(m_ConstrainedObject == null || m_SourceA == null || m_SourceB == null);
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
m_ConstrainedObject = null;
m_SourceA = null;
m_SourceB = null;
m_BlendPosition = true;
m_BlendRotation = true;
m_PositionWeight = 0.5f;
m_RotationWeight = 0.5f;
m_MaintainPositionOffsets = false;
m_MaintainRotationOffsets = false;
}
}
/// <summary>
/// Blend constraint.
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Blend Constraint")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/BlendConstraint.html")]
public class BlendConstraint : RigConstraint<
BlendConstraintJob,
BlendConstraintData,
BlendConstraintJobBinder<BlendConstraintData>
>
{
/// <inheritdoc />
protected override void OnValidate()
{
base.OnValidate();
m_Data.positionWeight = Mathf.Clamp01(m_Data.positionWeight);
m_Data.rotationWeight = Mathf.Clamp01(m_Data.rotationWeight);
}
}
}

View File

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

View File

@@ -0,0 +1,107 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The ChainIK constraint data.
/// </summary>
[System.Serializable]
public struct ChainIKConstraintData : IAnimationJobData, IChainIKConstraintData
{
internal const int k_MinIterations = 1;
internal const int k_MaxIterations = 50;
internal const float k_MinTolerance = 0f;
internal const float k_MaxTolerance = 0.01f;
[SerializeField] Transform m_Root;
[SerializeField] Transform m_Tip;
[SyncSceneToStream, SerializeField] Transform m_Target;
[SyncSceneToStream, SerializeField, Range(0f, 1f)] float m_ChainRotationWeight;
[SyncSceneToStream, SerializeField, Range(0f, 1f)] float m_TipRotationWeight;
[NotKeyable, SerializeField, Range(k_MinIterations, k_MaxIterations)] int m_MaxIterations;
[NotKeyable, SerializeField, Range(k_MinTolerance, k_MaxTolerance)] float m_Tolerance;
[NotKeyable, SerializeField] bool m_MaintainTargetPositionOffset;
[NotKeyable, SerializeField] bool m_MaintainTargetRotationOffset;
/// <inheritdoc />
public Transform root { get => m_Root; set => m_Root = value; }
/// <inheritdoc />
public Transform tip { get => m_Tip; set => m_Tip = value; }
/// <inheritdoc />
public Transform target { get => m_Target; set => m_Target = value; }
/// <summary>The weight for which ChainIK target has an effect on chain (up to tip Transform). This is a value in between 0 and 1.</summary>
public float chainRotationWeight { get => m_ChainRotationWeight; set => m_ChainRotationWeight = Mathf.Clamp01(value); }
/// <summary>The weight for which ChainIK target has and effect on tip Transform. This is a value in between 0 and 1.</summary>
public float tipRotationWeight { get => m_TipRotationWeight; set => m_TipRotationWeight = Mathf.Clamp01(value); }
/// <inheritdoc />
public int maxIterations { get => m_MaxIterations; set => m_MaxIterations = Mathf.Clamp(value, k_MinIterations, k_MaxIterations); }
/// <inheritdoc />
public float tolerance { get => m_Tolerance; set => m_Tolerance = Mathf.Clamp(value, k_MinTolerance, k_MaxTolerance); }
/// <inheritdoc />
public bool maintainTargetPositionOffset { get => m_MaintainTargetPositionOffset; set => m_MaintainTargetPositionOffset = value; }
/// <inheritdoc />
public bool maintainTargetRotationOffset { get => m_MaintainTargetRotationOffset; set => m_MaintainTargetRotationOffset = value; }
/// <inheritdoc />
string IChainIKConstraintData.chainRotationWeightFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_ChainRotationWeight));
/// <inheritdoc />
string IChainIKConstraintData.tipRotationWeightFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_TipRotationWeight));
/// <inheritdoc />
bool IAnimationJobData.IsValid()
{
if (m_Root == null || m_Tip == null || m_Target == null)
return false;
int count = 1;
Transform tmp = m_Tip;
while (tmp != null && tmp != m_Root)
{
tmp = tmp.parent;
++count;
}
return (tmp == m_Root && count > 2);
}
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
m_Root = null;
m_Tip = null;
m_Target = null;
m_ChainRotationWeight = 1f;
m_TipRotationWeight = 1f;
m_MaxIterations = 15;
m_Tolerance = 0.0001f;
m_MaintainTargetPositionOffset = false;
m_MaintainTargetRotationOffset = false;
}
}
/// <summary>
/// ChainIK constraint
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Chain IK Constraint")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/ChainIKConstraint.html")]
public class ChainIKConstraint : RigConstraint<
ChainIKConstraintJob,
ChainIKConstraintData,
ChainIKConstraintJobBinder<ChainIKConstraintData>
>
{
/// <inheritdoc />
protected override void OnValidate()
{
base.OnValidate();
m_Data.chainRotationWeight = Mathf.Clamp01(m_Data.chainRotationWeight);
m_Data.tipRotationWeight = Mathf.Clamp01(m_Data.tipRotationWeight);
m_Data.maxIterations = Mathf.Clamp(
m_Data.maxIterations, ChainIKConstraintData.k_MinIterations, ChainIKConstraintData.k_MaxIterations
);
m_Data.tolerance = Mathf.Clamp(
m_Data.tolerance, ChainIKConstraintData.k_MinTolerance, ChainIKConstraintData.k_MaxTolerance
);
}
}
}

View File

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

View File

@@ -0,0 +1,74 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The DampedTransform constraint data.
/// </summary>
[System.Serializable]
public struct DampedTransformData : IAnimationJobData, IDampedTransformData
{
[SerializeField] Transform m_ConstrainedObject;
[SyncSceneToStream, SerializeField] Transform m_Source;
[SyncSceneToStream, SerializeField, Range(0f, 1f)] float m_DampPosition;
[SyncSceneToStream, SerializeField, Range(0f, 1f)] float m_DampRotation;
[NotKeyable, SerializeField] bool m_MaintainAim;
/// <inheritdoc />
public Transform constrainedObject { get => m_ConstrainedObject; set => m_ConstrainedObject = value; }
/// <inheritdoc />
public Transform sourceObject { get => m_Source; set => m_Source = value; }
/// <summary>
/// Damp position weight. Defines how much of constrained object position follows source object position.
/// Constrained position will closely follow source object when set to 0, and will
/// not move when set to 1.
/// </summary>
public float dampPosition { get => m_DampPosition; set => m_DampPosition = Mathf.Clamp01(value); }
/// <summary>
/// Damp rotation weight. Defines how much of constrained object rotation follows source object rotation.
/// Constrained rotation will closely follow source object when set to 0, and will
/// not move when set to 1.
/// </summary>
public float dampRotation { get => m_DampRotation; set => m_DampRotation = Mathf.Clamp01(value); }
/// <inheritdoc />
public bool maintainAim { get => m_MaintainAim; set => m_MaintainAim = value; }
/// <inheritdoc />
string IDampedTransformData.dampPositionFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_DampPosition));
/// <inheritdoc />
string IDampedTransformData.dampRotationFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_DampRotation));
/// <inheritdoc />
bool IAnimationJobData.IsValid() => !(m_ConstrainedObject == null || m_Source == null);
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
m_ConstrainedObject = null;
m_Source = null;
m_DampPosition = 0.5f;
m_DampRotation = 0.5f;
m_MaintainAim = true;
}
}
/// <summary>
/// DampedTransform constraint.
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Damped Transform")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/DampedTransform.html")]
public class DampedTransform : RigConstraint<
DampedTransformJob,
DampedTransformData,
DampedTransformJobBinder<DampedTransformData>
>
{
/// <inheritdoc />
protected override void OnValidate()
{
base.OnValidate();
m_Data.dampPosition = Mathf.Clamp01(m_Data.dampPosition);
m_Data.dampRotation = Mathf.Clamp01(m_Data.dampRotation);
}
}
}

View File

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

View File

@@ -0,0 +1,214 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The MultiAim constraint data.
/// </summary>
[System.Serializable]
public struct MultiAimConstraintData : IAnimationJobData, IMultiAimConstraintData
{
/// <summary>
/// Axis type for MultiAimConstraint.
/// </summary>
public enum Axis
{
/// <summary>Positive X Axis (1, 0, 0)</summary>
X,
/// <summary>Negative X Axis (-1, 0, 0)</summary>
X_NEG,
/// <summary>Positive Y Axis (0, 1, 0)</summary>
Y,
/// <summary>Negative Y Axis (0, -1, 0)</summary>
Y_NEG,
/// <summary>Positive Z Axis (0, 0, 1)</summary>
Z,
/// <summary>Negative Z Axis (0, 0, -1)</summary>
Z_NEG
}
/// <summary>
/// Specifies how the world up vector used by the Multi-Aim constraint is defined.
/// </summary>
public enum WorldUpType
{
/// <summary>Neither defines nor uses a world up vector.</summary>
None,
/// <summary>Uses and defines the world up vector as the Unity Scene up vector (the Y axis).</summary>
SceneUp,
/// <summary>Uses and defines the world up vector as a vector from the constrained object, in the direction of the up object.</summary>
ObjectUp,
/// <summary>Uses and defines the world up vector as relative to the local space of the object.</summary>
ObjectRotationUp,
/// <summary>Uses and defines the world up vector as a vector specified by the user.</summary>
Vector
};
internal const float k_MinAngularLimit = -180f;
internal const float k_MaxAngularLimit = 180f;
[SerializeField] Transform m_ConstrainedObject;
[SyncSceneToStream, SerializeField, WeightRange(0f, 1f)] WeightedTransformArray m_SourceObjects;
[SyncSceneToStream, SerializeField] Vector3 m_Offset;
[SyncSceneToStream, SerializeField, Range(k_MinAngularLimit, k_MaxAngularLimit)] float m_MinLimit;
[SyncSceneToStream, SerializeField, Range(k_MinAngularLimit, k_MaxAngularLimit)] float m_MaxLimit;
[NotKeyable, SerializeField] Axis m_AimAxis;
[NotKeyable, SerializeField] Axis m_UpAxis;
[NotKeyable, SerializeField] WorldUpType m_WorldUpType;
[SyncSceneToStream, SerializeField] Transform m_WorldUpObject;
[NotKeyable, SerializeField] Axis m_WorldUpAxis;
[NotKeyable, SerializeField] bool m_MaintainOffset;
[NotKeyable, SerializeField] Vector3Bool m_ConstrainedAxes;
/// <inheritdoc />
public Transform constrainedObject { get => m_ConstrainedObject; set => m_ConstrainedObject = value; }
/// <inheritdoc />
public WeightedTransformArray sourceObjects
{
get => m_SourceObjects;
set => m_SourceObjects = value;
}
/// <inheritdoc />
public bool maintainOffset { get => m_MaintainOffset; set => m_MaintainOffset = value; }
/// <summary>
/// Post-Rotation offset applied to the constrained Transform.
/// </summary>
public Vector3 offset { get => m_Offset; set => m_Offset = value; }
/// <summary>
/// Minimum and maximum value of the rotation permitted for the constraint. The values are in degrees.
/// </summary>
public Vector2 limits
{
get => new Vector2(m_MinLimit, m_MaxLimit);
set
{
m_MinLimit = Mathf.Clamp(value.x, k_MinAngularLimit, k_MaxAngularLimit);
m_MaxLimit = Mathf.Clamp(value.y, k_MinAngularLimit, k_MaxAngularLimit);
}
}
/// <inheritdoc cref="IMultiAimConstraintData.aimAxis"/>
public Axis aimAxis { get => m_AimAxis; set => m_AimAxis = value; }
/// <inheritdoc cref="IMultiAimConstraintData.upAxis"/>
public Axis upAxis { get => m_UpAxis; set => m_UpAxis = value; }
/// <inheritdoc cref="IMultiAimConstraintData.worldUpType"/>
public WorldUpType worldUpType { get => m_WorldUpType; set => m_WorldUpType = value; }
/// <inheritdoc cref="IMultiAimConstraintData.aimAxis"/>
public Axis worldUpAxis { get => m_WorldUpAxis; set => m_WorldUpAxis = value; }
/// <inheritdoc />
public Transform worldUpObject { get => m_WorldUpObject; set => m_WorldUpObject = value; }
/// <inheritdoc />
public bool constrainedXAxis { get => m_ConstrainedAxes.x; set => m_ConstrainedAxes.x = value; }
/// <inheritdoc />
public bool constrainedYAxis { get => m_ConstrainedAxes.y; set => m_ConstrainedAxes.y = value; }
/// <inheritdoc />
public bool constrainedZAxis { get => m_ConstrainedAxes.z; set => m_ConstrainedAxes.z = value; }
/// <inheritdoc />
Vector3 IMultiAimConstraintData.aimAxis => Convert(m_AimAxis);
/// <inheritdoc />
Vector3 IMultiAimConstraintData.upAxis => Convert(m_UpAxis);
/// <inheritdoc />
int IMultiAimConstraintData.worldUpType => (int) m_WorldUpType;
/// <inheritdoc />
Vector3 IMultiAimConstraintData.worldUpAxis => Convert(m_WorldUpAxis);
/// <inheritdoc />
string IMultiAimConstraintData.offsetVector3Property => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_Offset));
/// <inheritdoc />
string IMultiAimConstraintData.minLimitFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_MinLimit));
/// <inheritdoc />
string IMultiAimConstraintData.maxLimitFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_MaxLimit));
/// <inheritdoc />
string IMultiAimConstraintData.sourceObjectsProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_SourceObjects));
/// <inheritdoc />
bool IAnimationJobData.IsValid()
{
if (m_ConstrainedObject == null || m_SourceObjects.Count == 0)
return false;
foreach (var src in m_SourceObjects)
if (src.transform == null)
return false;
return true;
}
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
m_ConstrainedObject = null;
m_UpAxis = Axis.Y;
m_AimAxis = Axis.Z;
m_WorldUpType = WorldUpType.None;
m_WorldUpAxis = Axis.Y;
m_WorldUpObject = null;
m_SourceObjects.Clear();
m_MaintainOffset = false;
m_Offset = Vector3.zero;
m_ConstrainedAxes = new Vector3Bool(true);
m_MinLimit = -180f;
m_MaxLimit = 180f;
}
static Vector3 Convert(Axis axis)
{
switch (axis)
{
case Axis.X:
return Vector3.right;
case Axis.X_NEG:
return Vector3.left;
case Axis.Y:
return Vector3.up;
case Axis.Y_NEG:
return Vector3.down;
case Axis.Z:
return Vector3.forward;
case Axis.Z_NEG:
return Vector3.back;
default:
return Vector3.up;
}
}
}
/// <summary>
/// MultiAim constraint.
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Multi-Aim Constraint")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/MultiAimConstraint.html")]
public class MultiAimConstraint : RigConstraint<
MultiAimConstraintJob,
MultiAimConstraintData,
MultiAimConstraintJobBinder<MultiAimConstraintData>
>
{
/// <inheritdoc />
protected override void OnValidate()
{
base.OnValidate();
var weights = m_Data.sourceObjects;
WeightedTransformArray.OnValidate(ref weights);
m_Data.sourceObjects = weights;
var limits = m_Data.limits;
limits.x = Mathf.Clamp(
limits.x, MultiAimConstraintData.k_MinAngularLimit, MultiAimConstraintData.k_MaxAngularLimit
);
limits.y = Mathf.Clamp(
limits.y, MultiAimConstraintData.k_MinAngularLimit, MultiAimConstraintData.k_MaxAngularLimit
);
m_Data.limits = limits;
}
}
}

View File

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

View File

@@ -0,0 +1,94 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The MultiParent constraint data.
/// </summary>
[System.Serializable]
public struct MultiParentConstraintData : IAnimationJobData, IMultiParentConstraintData
{
[SerializeField] Transform m_ConstrainedObject;
[SerializeField, SyncSceneToStream, WeightRange(0f, 1f)] WeightedTransformArray m_SourceObjects;
[NotKeyable, SerializeField] Vector3Bool m_ConstrainedPositionAxes;
[NotKeyable, SerializeField] Vector3Bool m_ConstrainedRotationAxes;
[NotKeyable, SerializeField] bool m_MaintainPositionOffset;
[NotKeyable, SerializeField] bool m_MaintainRotationOffset;
/// <inheritdoc />
public Transform constrainedObject { get => m_ConstrainedObject; set => m_ConstrainedObject = value; }
/// <inheritdoc />
public WeightedTransformArray sourceObjects
{
get => m_SourceObjects;
set => m_SourceObjects = value;
}
/// <inheritdoc />
public bool maintainPositionOffset { get => m_MaintainPositionOffset; set => m_MaintainPositionOffset = value; }
/// <inheritdoc />
public bool maintainRotationOffset { get => m_MaintainRotationOffset; set => m_MaintainRotationOffset = value; }
/// <inheritdoc />
public bool constrainedPositionXAxis { get => m_ConstrainedPositionAxes.x; set => m_ConstrainedPositionAxes.x = value; }
/// <inheritdoc />
public bool constrainedPositionYAxis { get => m_ConstrainedPositionAxes.y; set => m_ConstrainedPositionAxes.y = value; }
/// <inheritdoc />
public bool constrainedPositionZAxis { get => m_ConstrainedPositionAxes.z; set => m_ConstrainedPositionAxes.z = value; }
/// <inheritdoc />
public bool constrainedRotationXAxis { get => m_ConstrainedRotationAxes.x; set => m_ConstrainedRotationAxes.x = value; }
/// <inheritdoc />
public bool constrainedRotationYAxis { get => m_ConstrainedRotationAxes.y; set => m_ConstrainedRotationAxes.y = value; }
/// <inheritdoc />
public bool constrainedRotationZAxis { get => m_ConstrainedRotationAxes.z; set => m_ConstrainedRotationAxes.z = value; }
/// <inheritdoc />
string IMultiParentConstraintData.sourceObjectsProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_SourceObjects));
/// <inheritdoc />
bool IAnimationJobData.IsValid()
{
if (m_ConstrainedObject == null || m_SourceObjects.Count == 0)
return false;
foreach (var src in m_SourceObjects)
if (src.transform == null)
return false;
return true;
}
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
m_ConstrainedObject = null;
m_ConstrainedPositionAxes = new Vector3Bool(true);
m_ConstrainedRotationAxes = new Vector3Bool(true);
m_SourceObjects.Clear();
m_MaintainPositionOffset = false;
m_MaintainRotationOffset = false;
}
}
/// <summary>
/// MultiParent constraint
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Multi-Parent Constraint")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/MultiParentConstraint.html")]
public class MultiParentConstraint : RigConstraint<
MultiParentConstraintJob,
MultiParentConstraintData,
MultiParentConstraintJobBinder<MultiParentConstraintData>
>
{
/// <inheritdoc />
protected override void OnValidate()
{
base.OnValidate();
var weights = m_Data.sourceObjects;
WeightedTransformArray.OnValidate(ref weights);
m_Data.sourceObjects = weights;
}
}
}

View File

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

View File

@@ -0,0 +1,89 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The MultiPosition constraint job.
/// </summary>
[System.Serializable]
public struct MultiPositionConstraintData : IAnimationJobData, IMultiPositionConstraintData
{
[SerializeField] Transform m_ConstrainedObject;
[SyncSceneToStream, SerializeField, WeightRange(0f, 1f)] WeightedTransformArray m_SourceObjects;
[SyncSceneToStream, SerializeField] Vector3 m_Offset;
[NotKeyable, SerializeField] Vector3Bool m_ConstrainedAxes;
[NotKeyable, SerializeField] bool m_MaintainOffset;
/// <inheritdoc />
public Transform constrainedObject { get => m_ConstrainedObject; set => m_ConstrainedObject = value; }
/// <inheritdoc />
public WeightedTransformArray sourceObjects
{
get => m_SourceObjects;
set => m_SourceObjects = value;
}
/// <inheritdoc />
public bool maintainOffset { get => m_MaintainOffset; set => m_MaintainOffset = value; }
/// <summary>Post-Translation offset applied to the constrained Transform.</summary>
public Vector3 offset { get => m_Offset; set => m_Offset = value; }
/// <inheritdoc />
public bool constrainedXAxis { get => m_ConstrainedAxes.x; set => m_ConstrainedAxes.x = value; }
/// <inheritdoc />
public bool constrainedYAxis { get => m_ConstrainedAxes.y; set => m_ConstrainedAxes.y = value; }
/// <inheritdoc />
public bool constrainedZAxis { get => m_ConstrainedAxes.z; set => m_ConstrainedAxes.z = value; }
/// <inheritdoc />
string IMultiPositionConstraintData.offsetVector3Property => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_Offset));
/// <inheritdoc />
string IMultiPositionConstraintData.sourceObjectsProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_SourceObjects));
/// <inheritdoc />
bool IAnimationJobData.IsValid()
{
if (m_ConstrainedObject == null || m_SourceObjects.Count == 0)
return false;
foreach (var src in m_SourceObjects)
if (src.transform == null)
return false;
return true;
}
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
m_ConstrainedObject = null;
m_ConstrainedAxes = new Vector3Bool(true);
m_SourceObjects.Clear();
m_MaintainOffset = false;
m_Offset = Vector3.zero;
}
}
/// <summary>
/// MultiPosition constraint.
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Multi-Position Constraint")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/MultiPositionConstraint.html")]
public class MultiPositionConstraint : RigConstraint<
MultiPositionConstraintJob,
MultiPositionConstraintData,
MultiPositionConstraintJobBinder<MultiPositionConstraintData>
>
{
/// <inheritdoc />
protected override void OnValidate()
{
base.OnValidate();
var weights = m_Data.sourceObjects;
WeightedTransformArray.OnValidate(ref weights);
m_Data.sourceObjects = weights;
}
}
}

View File

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

View File

@@ -0,0 +1,91 @@
using System.Collections.Generic;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The MultiReferential constraint data.
/// </summary>
[System.Serializable]
public struct MultiReferentialConstraintData : IAnimationJobData, IMultiReferentialConstraintData
{
[SyncSceneToStream, SerializeField] int m_Driver;
[SyncSceneToStream, SerializeField] List<Transform> m_SourceObjects;
/// <summary>The driver index. This is a value in between 0 and the number of sourceObjects.</summary>
public int driver
{
get => m_Driver;
set => m_Driver = Mathf.Clamp(value, 0, m_SourceObjects.Count - 1);
}
/// <summary>The list of Transforms that are affected by the specified driver.</summary>
public List<Transform> sourceObjects
{
get
{
if (m_SourceObjects == null)
m_SourceObjects = new List<Transform>();
return m_SourceObjects;
}
set
{
m_SourceObjects = value;
m_Driver = Mathf.Clamp(m_Driver, 0, m_SourceObjects.Count - 1);
}
}
/// <inheritdoc />
Transform[] IMultiReferentialConstraintData.sourceObjects => m_SourceObjects.ToArray();
/// <inheritdoc />
int IMultiReferentialConstraintData.driverValue => m_Driver;
/// <inheritdoc />
string IMultiReferentialConstraintData.driverIntProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_Driver));
/// <inheritdoc />
bool IAnimationJobData.IsValid()
{
if (m_SourceObjects.Count < 2)
return false;
foreach (var src in m_SourceObjects)
if (src == null)
return false;
return true;
}
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
m_Driver = 0;
m_SourceObjects = new List<Transform>();
}
/// <summary>
/// Updates the driver index to match the number of source objects.
/// </summary>
public void UpdateDriver() =>
m_Driver = Mathf.Clamp(m_Driver, 0, m_SourceObjects != null ? m_SourceObjects.Count - 1 : 0);
}
/// <summary>
/// MultiReferential constraint.
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Multi-Referential Constraint")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/MultiReferentialConstraint.html")]
public class MultiReferentialConstraint : RigConstraint<
MultiReferentialConstraintJob,
MultiReferentialConstraintData,
MultiReferentialConstraintJobBinder<MultiReferentialConstraintData>
>
{
/// <inheritdoc />
protected override void OnValidate()
{
base.OnValidate();
m_Data.UpdateDriver();
}
}
}

View File

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

View File

@@ -0,0 +1,88 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The MultiRotation constraint job.
/// </summary>
[System.Serializable]
public struct MultiRotationConstraintData : IAnimationJobData, IMultiRotationConstraintData
{
[SerializeField] Transform m_ConstrainedObject;
[SyncSceneToStream, SerializeField, WeightRange(0f, 1f)] WeightedTransformArray m_SourceObjects;
[SyncSceneToStream, SerializeField] Vector3 m_Offset;
[NotKeyable, SerializeField] Vector3Bool m_ConstrainedAxes;
[NotKeyable, SerializeField] bool m_MaintainOffset;
/// <inheritdoc />
public Transform constrainedObject { get => m_ConstrainedObject; set => m_ConstrainedObject = value; }
/// <inheritdoc />
public WeightedTransformArray sourceObjects
{
get => m_SourceObjects;
set => m_SourceObjects = value;
}
/// <inheritdoc />
public bool maintainOffset { get => m_MaintainOffset; set => m_MaintainOffset = value; }
/// <summary>Post-Rotation offset applied to the constrained Transform.</summary>
public Vector3 offset { get => m_Offset; set => m_Offset = value; }
/// <inheritdoc />
public bool constrainedXAxis { get => m_ConstrainedAxes.x; set => m_ConstrainedAxes.x = value; }
/// <inheritdoc />
public bool constrainedYAxis { get => m_ConstrainedAxes.y; set => m_ConstrainedAxes.y = value; }
/// <inheritdoc />
public bool constrainedZAxis { get => m_ConstrainedAxes.z; set => m_ConstrainedAxes.z = value; }
/// <inheritdoc />
string IMultiRotationConstraintData.offsetVector3Property => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_Offset));
/// <inheritdoc />
string IMultiRotationConstraintData.sourceObjectsProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_SourceObjects));
/// <inheritdoc />
bool IAnimationJobData.IsValid()
{
if (m_ConstrainedObject == null || m_SourceObjects.Count == 0)
return false;
foreach (var src in m_SourceObjects)
if (src.transform == null)
return false;
return true;
}
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
m_ConstrainedObject = null;
m_ConstrainedAxes = new Vector3Bool(true);
m_SourceObjects.Clear();
m_MaintainOffset = false;
m_Offset = Vector3.zero;
}
}
/// <summary>
/// MultiRotation constraint.
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Multi-Rotation Constraint")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/MultiRotationConstraint.html")]
public class MultiRotationConstraint : RigConstraint<
MultiRotationConstraintJob,
MultiRotationConstraintData,
MultiRotationConstraintJobBinder<MultiRotationConstraintData>
>
{
/// <inheritdoc />
protected override void OnValidate()
{
base.OnValidate();
var weights = m_Data.sourceObjects;
WeightedTransformArray.OnValidate(ref weights);
m_Data.sourceObjects = weights;
}
}
}

View File

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

View File

@@ -0,0 +1,95 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The OverrideTransform constraint data.
/// </summary>
[System.Serializable]
public struct OverrideTransformData : IAnimationJobData, IOverrideTransformData
{
/// <summary>
/// The override space controls how the override source Transform
/// is copied unto constrained Transform.
/// </summary>
[System.Serializable]
public enum Space
{
/// <summary>Copy override world TR components into world TR components of the constrained Transform.</summary>
World = OverrideTransformJob.Space.World,
/// <summary>Copy override local TR components into local TR components of the constrained Transform.</summary>
Local = OverrideTransformJob.Space.Local,
/// <summary>Add override local TR components to local TR components of the constrained Transform. </summary>
Pivot = OverrideTransformJob.Space.Pivot
}
[SerializeField] Transform m_ConstrainedObject;
[SyncSceneToStream, SerializeField] Transform m_OverrideSource;
[SyncSceneToStream, SerializeField] Vector3 m_OverridePosition;
[SyncSceneToStream, SerializeField] Vector3 m_OverrideRotation;
[SyncSceneToStream, SerializeField, Range(0f, 1f)] float m_PositionWeight;
[SyncSceneToStream, SerializeField, Range(0f, 1f)] float m_RotationWeight;
[NotKeyable, SerializeField] Space m_Space;
/// <inheritdoc />
public Transform constrainedObject { get => m_ConstrainedObject; set => m_ConstrainedObject = value; }
/// <inheritdoc />
public Transform sourceObject { get => m_OverrideSource; set => m_OverrideSource = value; }
/// <summary>The override space.</summary>
public Space space { get => m_Space; set => m_Space = value; }
/// <summary>The override position. This is taken into account only if sourceObject is null.</summary>
public Vector3 position { get => m_OverridePosition; set => m_OverridePosition = value; }
/// <summary>The override rotation. This is taken into account only if sourceObject is null.</summary>
public Vector3 rotation { get => m_OverrideRotation; set => m_OverrideRotation = value; }
/// <summary>The weight for which override position has an effect on constrained Transform. This is a value in between 0 and 1.</summary>
public float positionWeight { get => m_PositionWeight; set => m_PositionWeight = Mathf.Clamp01(value); }
/// <summary>The weight for which override rotation has an effect on constrained Transform. This is a value in between 0 and 1.</summary>
public float rotationWeight { get => m_RotationWeight; set => m_RotationWeight = Mathf.Clamp01(value); }
/// <inheritdoc />
int IOverrideTransformData.space => (int)m_Space;
/// <inheritdoc />
string IOverrideTransformData.positionWeightFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_PositionWeight));
/// <inheritdoc />
string IOverrideTransformData.rotationWeightFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_RotationWeight));
/// <inheritdoc />
string IOverrideTransformData.positionVector3Property => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_OverridePosition));
/// <inheritdoc />
string IOverrideTransformData.rotationVector3Property => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_OverrideRotation));
/// <inheritdoc />
bool IAnimationJobData.IsValid() => m_ConstrainedObject != null;
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
m_ConstrainedObject = null;
m_OverrideSource = null;
m_OverridePosition = Vector3.zero;
m_OverrideRotation = Vector3.zero;
m_Space = Space.Pivot;
m_PositionWeight = 1f;
m_RotationWeight = 1f;
}
}
/// <summary>
/// OverrideTransform constraint.
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Override Transform")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/OverrideTransform.html")]
public class OverrideTransform : RigConstraint<
OverrideTransformJob,
OverrideTransformData,
OverrideTransformJobBinder<OverrideTransformData>
>
{
/// <inheritdoc />
protected override void OnValidate()
{
base.OnValidate();
m_Data.positionWeight = Mathf.Clamp01(m_Data.positionWeight);
m_Data.rotationWeight = Mathf.Clamp01(m_Data.rotationWeight);
}
}
}

View File

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

View File

@@ -0,0 +1,53 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The TwistChain constraint data.
/// </summary>
[System.Serializable]
public struct TwistChainConstraintData : IAnimationJobData, ITwistChainConstraintData
{
[SerializeField] private Transform m_Root;
[SerializeField] private Transform m_Tip;
[SyncSceneToStream, SerializeField] private Transform m_RootTarget;
[SyncSceneToStream, SerializeField] private Transform m_TipTarget;
[SerializeField] private AnimationCurve m_Curve;
/// <inheritdoc />
public Transform root { get => m_Root; set => m_Root = value; }
/// <inheritdoc />
public Transform tip { get => m_Tip; set => m_Tip = value; }
/// <inheritdoc />
public Transform rootTarget { get => m_RootTarget; set => m_RootTarget = value; }
/// <inheritdoc />
public Transform tipTarget { get => m_TipTarget; set => m_TipTarget = value; }
/// <inheritdoc />
public AnimationCurve curve { get => m_Curve; set => m_Curve = value; }
/// <inheritdoc />
bool IAnimationJobData.IsValid() => !(root == null || tip == null || !tip.IsChildOf(root) || rootTarget == null || tipTarget == null || curve == null);
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
root = tip = rootTarget = tipTarget = null;
curve = AnimationCurve.Linear(0f, 0f, 1f, 1f);
}
}
/// <summary>
/// TwistChain constraint
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Twist Chain Constraint")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/TwistChainConstraint.html")]
public class TwistChainConstraint : RigConstraint<
TwistChainConstraintJob,
TwistChainConstraintData,
TwistChainConstraintJobBinder<TwistChainConstraintData>
>
{
}
}

View File

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

View File

@@ -0,0 +1,101 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The TwistCorrection constraint data.
/// </summary>
[System.Serializable]
public struct TwistCorrectionData : IAnimationJobData, ITwistCorrectionData
{
/// <summary>
/// Axis type for TwistCorrection.
/// </summary>
public enum Axis
{
/// <summary>X Axis.</summary>
X,
/// <summary>Y Axis.</summary>
Y,
/// <summary>Z Axis.</summary>
Z
}
[SyncSceneToStream, SerializeField] Transform m_Source;
[NotKeyable, SerializeField] Axis m_TwistAxis;
[SyncSceneToStream, SerializeField, WeightRange(-1f, 1f)] WeightedTransformArray m_TwistNodes;
/// <summary>The source Transform that influences the twist nodes.</summary>
public Transform sourceObject { get => m_Source; set => m_Source = value; }
/// <inheritdoc />
public WeightedTransformArray twistNodes
{
get => m_TwistNodes;
set => m_TwistNodes = value;
}
/// <inheritdoc />
public Axis twistAxis { get => m_TwistAxis; set => m_TwistAxis = value; }
/// <inheritdoc />
Transform ITwistCorrectionData.source => m_Source;
/// <inheritdoc />
Vector3 ITwistCorrectionData.twistAxis => Convert(m_TwistAxis);
/// <inheritdoc />
string ITwistCorrectionData.twistNodesProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_TwistNodes));
static Vector3 Convert(Axis axis)
{
if (axis == Axis.X)
return Vector3.right;
if (axis == Axis.Y)
return Vector3.up;
return Vector3.forward;
}
/// <inheritdoc />
bool IAnimationJobData.IsValid()
{
if (m_Source == null)
return false;
for (int i = 0; i < m_TwistNodes.Count; ++i)
if (m_TwistNodes[i].transform == null)
return false;
return true;
}
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
m_Source = null;
m_TwistAxis = Axis.Z;
m_TwistNodes.Clear();
}
}
/// <summary>
/// TwistCorrection constraint.
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Twist Correction")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/TwistCorrection.html")]
public class TwistCorrection : RigConstraint<
TwistCorrectionJob,
TwistCorrectionData,
TwistCorrectionJobBinder<TwistCorrectionData>
>
{
/// <inheritdoc />
protected override void OnValidate()
{
base.OnValidate();
var weights = m_Data.twistNodes;
WeightedTransformArray.OnValidate(ref weights, -1f, 1f);
m_Data.twistNodes = weights;
}
}
}

View File

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

View File

@@ -0,0 +1,91 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The TwoBoneIK constraint data.
/// </summary>
[System.Serializable]
public struct TwoBoneIKConstraintData : IAnimationJobData, ITwoBoneIKConstraintData
{
[SerializeField] Transform m_Root;
[SerializeField] Transform m_Mid;
[SerializeField] Transform m_Tip;
[SyncSceneToStream, SerializeField] Transform m_Target;
[SyncSceneToStream, SerializeField] Transform m_Hint;
[SyncSceneToStream, SerializeField, Range(0f, 1f)] float m_TargetPositionWeight;
[SyncSceneToStream, SerializeField, Range(0f, 1f)] float m_TargetRotationWeight;
[SyncSceneToStream, SerializeField, Range(0f, 1f)] float m_HintWeight;
[NotKeyable, SerializeField] bool m_MaintainTargetPositionOffset;
[NotKeyable, SerializeField] bool m_MaintainTargetRotationOffset;
/// <inheritdoc />
public Transform root { get => m_Root; set => m_Root = value; }
/// <inheritdoc />
public Transform mid { get => m_Mid; set => m_Mid = value; }
/// <inheritdoc />
public Transform tip { get => m_Tip; set => m_Tip = value; }
/// <inheritdoc />
public Transform target { get => m_Target; set => m_Target = value; }
/// <inheritdoc />
public Transform hint { get => m_Hint; set => m_Hint = value; }
/// <summary>The weight for which target position has an effect on IK calculations. This is a value in between 0 and 1.</summary>
public float targetPositionWeight { get => m_TargetPositionWeight; set => m_TargetPositionWeight = Mathf.Clamp01(value); }
/// <summary>The weight for which target rotation has an effect on IK calculations. This is a value in between 0 and 1.</summary>
public float targetRotationWeight { get => m_TargetRotationWeight; set => m_TargetRotationWeight = Mathf.Clamp01(value); }
/// <summary>The weight for which hint transform has an effect on IK calculations. This is a value in between 0 and 1.</summary>
public float hintWeight { get => m_HintWeight; set => m_HintWeight = Mathf.Clamp01(value); }
/// <inheritdoc />
public bool maintainTargetPositionOffset { get => m_MaintainTargetPositionOffset; set => m_MaintainTargetPositionOffset = value; }
/// <inheritdoc />
public bool maintainTargetRotationOffset { get => m_MaintainTargetRotationOffset; set => m_MaintainTargetRotationOffset = value; }
/// <inheritdoc />
string ITwoBoneIKConstraintData.targetPositionWeightFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_TargetPositionWeight));
/// <inheritdoc />
string ITwoBoneIKConstraintData.targetRotationWeightFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_TargetRotationWeight));
/// <inheritdoc />
string ITwoBoneIKConstraintData.hintWeightFloatProperty => ConstraintsUtils.ConstructConstraintDataPropertyName(nameof(m_HintWeight));
/// <inheritdoc />
bool IAnimationJobData.IsValid() => (m_Tip != null && m_Mid != null && m_Root != null && m_Target != null && m_Tip.IsChildOf(m_Mid) && m_Mid.IsChildOf(m_Root));
/// <inheritdoc />
void IAnimationJobData.SetDefaultValues()
{
m_Root = null;
m_Mid = null;
m_Tip = null;
m_Target = null;
m_Hint = null;
m_TargetPositionWeight = 1f;
m_TargetRotationWeight = 1f;
m_HintWeight = 1f;
m_MaintainTargetPositionOffset = false;
m_MaintainTargetRotationOffset = false;
}
}
/// <summary>
/// TwoBoneIK constraint
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Two Bone IK Constraint")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/constraints/TwoBoneIKConstraint.html")]
public class TwoBoneIKConstraint : RigConstraint<
TwoBoneIKConstraintJob,
TwoBoneIKConstraintData,
TwoBoneIKConstraintJobBinder<TwoBoneIKConstraintData>
>
{
/// <inheritdoc />
protected override void OnValidate()
{
base.OnValidate();
m_Data.hintWeight = Mathf.Clamp01(m_Data.hintWeight);
m_Data.targetPositionWeight = Mathf.Clamp01(m_Data.targetPositionWeight);
m_Data.targetRotationWeight = Mathf.Clamp01(m_Data.targetRotationWeight);
}
}
}

View File

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

View File

@@ -0,0 +1,51 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// This interface is used to represent all constraints classes.
/// </summary>
public interface IRigConstraint
{
/// <summary>
/// Retrieves the constraint valid state.
/// </summary>
/// <returns>Returns true if constraint data can be successfully evaluated. Returns false otherwise.</returns>
bool IsValid();
/// <summary>
/// Creates the animation job for this constraint.
/// </summary>
/// <param name="animator">The animated hierarchy Animator component.</param>
/// <returns>Returns the newly instantiated job.</returns>
IAnimationJob CreateJob(Animator animator);
/// <summary>
/// Updates the specified job data.
/// </summary>
/// <param name="job">The job to update.</param>
void UpdateJob(IAnimationJob job);
/// <summary>
/// Frees the specified job memory.
/// </summary>
/// <param name="job">The job to destroy.</param>
void DestroyJob(IAnimationJob job);
/// <summary>
/// The data container for the constraint.
/// </summary>
IAnimationJobData data { get; }
/// <summary>
/// The job binder for the constraint.
/// </summary>
IAnimationJobBinder binder { get; }
/// <summary>
/// The component for the constraint.
/// </summary>
Component component { get; }
/// <summary>
/// The constraint weight. This is a value in between 0 and 1.
/// </summary>
float weight { get; set; }
}
}

View File

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

View File

@@ -0,0 +1,42 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// Interface for rig layers.
/// </summary>
public interface IRigLayer
{
/// <summary>The Rig associated to the IRigLayer</summary>
Rig rig { get; }
/// <summary>The list of constraints associated with the IRigLayer.</summary>
IRigConstraint[] constraints { get; }
/// <summary>The list of jobs built from constraints associated with the IRigLayer.</summary>
IAnimationJob[] jobs { get; }
/// <summary>The active state. True if the IRigLayer is active, false otherwise.</summary>
bool active { get; }
/// <summary>The IRigLayer name.</summary>
string name { get; }
/// <summary>
/// Initializes the IRigLayer
/// </summary>
/// <param name="animator">The Animator used to animate the IRigLayer constraints.</param>
/// <returns>True if IRigLayer was initialized properly, false otherwise.</returns>
bool Initialize(Animator animator);
/// <summary>
/// Updates the IRigLayer jobs.
/// </summary>
void Update();
/// <summary>
/// Resets the IRigLayer.
/// </summary>
void Reset();
/// <summary>
/// Queries whether the IRigLayer is valid.
/// </summary>
/// <returns>True if IRigLayer is valid, false otherwise.</returns>
bool IsValid();
}
}

View File

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

View File

@@ -0,0 +1,96 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// Use this class to define an override rig constraint on another rig constraint.
/// While the overriden constraint data remains the same, the job is overriden.
/// </summary>
/// <typeparam name="TConstraint">The base constraint to override</typeparam>
/// <typeparam name="TJob">The override job</typeparam>
/// <typeparam name="TData">The constraint data</typeparam>
/// <typeparam name="TBinder">The override constraint job binder</typeparam>
public class OverrideRigConstraint<TConstraint, TJob, TData, TBinder> : IRigConstraint
where TConstraint : MonoBehaviour, IRigConstraint
where TJob : struct, IWeightedAnimationJob
where TData : struct, IAnimationJobData
where TBinder : AnimationJobBinder<TJob, TData>, new()
{
/// <summary>
/// The base constraint.
/// </summary>
[SerializeField]
protected TConstraint m_Constraint;
static readonly TBinder s_Binder = new TBinder();
/// <summary>
/// Constructor
/// </summary>
/// <param name="baseConstraint">The constraint to override.</param>
public OverrideRigConstraint(TConstraint baseConstraint)
{
m_Constraint = baseConstraint;
}
/// <summary>
/// Creates the animation job for this constraint.
/// </summary>
/// <param name="animator">The animated hierarchy Animator component.</param>
/// <returns>Returns the newly instantiated job.</returns>
public IAnimationJob CreateJob(Animator animator)
{
IAnimationJobBinder binder = (IAnimationJobBinder)s_Binder;
TJob job = (TJob)binder.Create(animator, m_Constraint.data, m_Constraint);
// Bind constraint job weight property
job.jobWeight = FloatProperty.BindCustom(
animator,
ConstraintsUtils.ConstructCustomPropertyName(m_Constraint, ConstraintProperties.s_Weight)
);
return job;
}
/// <summary>
/// Frees the specified job memory.
/// </summary>
/// <param name="job"></param>
public void DestroyJob(IAnimationJob job) => s_Binder.Destroy((TJob)job);
/// <summary>
/// Updates the specified job data.
/// </summary>
/// <param name="job"></param>
public void UpdateJob(IAnimationJob job)
{
IAnimationJobBinder binder = (IAnimationJobBinder)s_Binder;
binder.Update(job, m_Constraint.data);
}
/// <summary>
/// Retrieves the constraint valid state.
/// </summary>
/// <returns>Returns true if constraint data can be successfully evaluated. Returns false otherwise.</returns>
public bool IsValid()
{
return m_Constraint.IsValid();
}
/// <summary>
/// The job binder for the constraint.
/// </summary>
IAnimationJobBinder IRigConstraint.binder => s_Binder;
/// <summary>
/// The data container for the constraint.
/// </summary>
IAnimationJobData IRigConstraint.data => m_Constraint.data;
/// <summary>
/// The component for the constraint.
/// </summary>
Component IRigConstraint.component => m_Constraint.component;
/// <summary>
/// The constraint weight. This is a value between 0 and 1.
/// </summary>
public float weight { get => m_Constraint.weight; set => m_Constraint.weight = value; }
}
}

View File

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

View File

@@ -0,0 +1,115 @@
using System;
using UnityEngine.Serialization;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The OverrideRigLayer is used to override constraints normally evaluated by
/// a specified Rig component.
/// </summary>
[Serializable]
public class OverrideRigLayer : IRigLayer
{
[SerializeField] [FormerlySerializedAs("rig")] private Rig m_Rig;
[SerializeField] [FormerlySerializedAs("active")] private bool m_Active = true;
private IRigConstraint[] m_Constraints;
private IAnimationJob[] m_Jobs;
/// <summary>The Rig associated to the OverrideRigLayer</summary>
public Rig rig { get => m_Rig; private set => m_Rig = value; }
/// <summary>The active state. True if the OverrideRigLayer is active, false otherwise.</summary>
public bool active { get => m_Active; set => m_Active = value; }
/// <summary>The OverrideRigLayer name.</summary>
public string name { get => (rig != null ? rig.gameObject.name : "no-name"); }
/// <summary>The list of constraints associated with the OverrideRigLayer.</summary>
public IRigConstraint[] constraints { get => isInitialized ? m_Constraints : null; }
/// <summary>The list of jobs built from constraints associated with the OverrideRigLayer.</summary>
public IAnimationJob[] jobs { get => isInitialized ? m_Jobs : null; }
/// <summary>Returns true if OverrideRigLayer was initialized or false otherwise.</summary>
/// <seealso cref="RigLayer.Initialize"/>
public bool isInitialized { get; private set; }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="rig">The rig represented by this override rig layer.</param>
/// <param name="constraints">The constraints that override those of the rig.</param>
/// <param name="active">The active state of the override rig layer.</param>
public OverrideRigLayer(Rig rig, IRigConstraint[] constraints, bool active = true)
{
this.rig = rig;
this.active = active;
m_Constraints = constraints;
}
/// <summary>
/// Initializes the OverrideRigLayer. This will create animation jobs using
/// the rig constraints provided to the OverrideRigLayer.
/// </summary>
/// <param name="animator">The Animator used to animate the RigLayer constraints.</param>
/// <returns>True if RigLayer was initialized properly, false otherwise.</returns>
public bool Initialize(Animator animator)
{
if (isInitialized)
return true;
if (rig == null)
return false;
if (m_Constraints == null || m_Constraints.Length == 0)
return false;
m_Jobs = new IAnimationJob[m_Constraints.Length];
for (int i = 0; i < m_Constraints.Length; ++i)
{
m_Jobs[i] = m_Constraints[i].CreateJob(animator);
}
return isInitialized = true;
}
/// <summary>
/// Updates the OverrideRigLayer jobs. This is called during the Update loop before
/// the Animator evaluates the PlayableGraph.
/// </summary>
public void Update()
{
if (!isInitialized)
return;
for (int i = 0; i < m_Constraints.Length; ++i)
{
m_Constraints[i].UpdateJob(m_Jobs[i]);
}
}
/// <summary>
/// Resets the OverrideRigLayer. This will destroy the animation jobs and
/// free up memory.
/// </summary>
public void Reset()
{
if (!isInitialized)
return;
for (int i = 0, count = m_Constraints.Length; i < count; ++i)
{
m_Constraints[i].DestroyJob(m_Jobs[i]);
}
m_Constraints = null;
m_Jobs = null;
isInitialized = false;
}
/// <summary>
/// Queries whether the OverrideRigLayer is valid.
/// </summary>
/// <returns>True if OverrideRigLayer is valid, false otherwise.</returns>
public bool IsValid() => rig != null && isInitialized;
}
}

View File

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

View File

@@ -0,0 +1,46 @@
using System.Collections.Generic;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The Rig component is used to group constraints under its GameObject local hierarchy.
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Setup/Rig")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/RiggingWorkflow.html#rig-component")]
public class Rig : MonoBehaviour, IRigEffectorHolder
{
[SerializeField, Range(0f, 1f)]
private float m_Weight = 1f;
/// <summary>The weight given to this rig and its associated constraints. This is a value in between 0 and 1.</summary>
public float weight { get => m_Weight; set => m_Weight = Mathf.Clamp01(value); }
[SerializeField] private List<RigEffectorData> m_Effectors = new List<RigEffectorData>();
#if UNITY_EDITOR
/// <inheritdoc />
public IEnumerable<RigEffectorData> effectors { get => m_Effectors; }
/// <inheritdoc />
public void AddEffector(Transform transform, RigEffectorData.Style style)
{
var effector = new RigEffectorData();
effector.Initialize(transform, style);
m_Effectors.Add(effector);
}
/// <inheritdoc />
public void RemoveEffector(Transform transform)
{
m_Effectors.RemoveAll((RigEffectorData data) => data.transform == transform);
}
/// <inheritdoc />
public bool ContainsEffector(Transform transform)
{
return m_Effectors.Exists((RigEffectorData data) => data.transform == transform);
}
#endif
}
}

View File

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

View File

@@ -0,0 +1,349 @@
using System.Collections.Generic;
using UnityEngine.Playables;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// RigBuilder is the root component that holds the Rigs that create an Animation Rigging hierarchy.
/// Its purpose is to create the PlayableGraph that will be used in the associated Animator component to animate
/// a character with constraints.
/// </summary>
[RequireComponent(typeof(Animator))]
[DisallowMultipleComponent, ExecuteInEditMode, AddComponentMenu("Animation Rigging/Setup/Rig Builder")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/RiggingWorkflow.html#rig-builder-component")]
public class RigBuilder : MonoBehaviour, IAnimationWindowPreview, IRigEffectorHolder
{
[SerializeField] private List<RigLayer> m_RigLayers;
private IRigLayer[] m_RuntimeRigLayers;
private SyncSceneToStreamLayer m_SyncSceneToStreamLayer;
[SerializeField] private List<RigEffectorData> m_Effectors = new List<RigEffectorData>();
private bool m_IsInPreview;
#if UNITY_EDITOR
/// <inheritdoc />
public IEnumerable<RigEffectorData> effectors { get => m_Effectors; }
#endif
/// <summary>
/// Delegate function that covers a RigBuilder calling OnEnable.
/// </summary>
/// <param name="rigBuilder">The RigBuilder component</param>
public delegate void OnAddRigBuilderCallback(RigBuilder rigBuilder);
/// <summary>
/// Delegate function that covers a RigBuilder calling OnDisable.
/// </summary>
/// <param name="rigBuilder">The RigBuilder component</param>
public delegate void OnRemoveRigBuilderCallback(RigBuilder rigBuilder);
/// <summary>
/// Notification callback that is sent whenever a RigBuilder calls OnEnable.
/// </summary>
public static OnAddRigBuilderCallback onAddRigBuilder;
/// <summary>
/// Notification callback that is sent whenever a RigBuilder calls OnDisable.
/// </summary>
public static OnRemoveRigBuilderCallback onRemoveRigBuilder;
void OnEnable()
{
// Build runtime data.
if (Application.isPlaying)
Build();
onAddRigBuilder?.Invoke(this);
}
void OnDisable()
{
// Clear runtime data.
if (Application.isPlaying)
Clear();
onRemoveRigBuilder?.Invoke(this);
}
void OnDestroy()
{
Clear();
}
/// <summary>
/// Updates the RigBuilder layers and evaluates the PlayableGraph manually.
/// </summary>
/// <param name="deltaTime">The time in seconds by which to advance the RigBuilder PlayableGraph.</param>
/// <example>
/// Manually evaluate the RigBuilder in LateUpdate.
/// <code source="../../DocCodeExamples/CustomRigBuilderEvaluator.cs" language="csharp" region="custom-rig-builder-evaluator"/>
/// </example>
public void Evaluate(float deltaTime)
{
if (!graph.IsValid())
return;
SyncLayers();
graph.Evaluate(deltaTime);
}
void Update()
{
if (!graph.IsValid())
return;
SyncLayers();
}
/// <summary>
/// Synchronizes rigs and constraints with scene values.
/// This must be called before evaluating the PlayableGraph.
/// </summary>
/// <seealso cref="RigBuilder.Build(PlayableGraph)"/>
/// <seealso cref="SyncSceneToStreamAttribute"/>
/// <seealso cref="AnimationJobBinder{TJob,TData}.Update"/>
/// <example>
/// Synchronizing layers before evaluating a PlayableGraph created
/// outside the RigBuilder in LateUpdate.
/// <code source="../../DocCodeExamples/CustomPlayableGraphEvaluator.cs" language="csharp" region="custom-playable-graph-evaluator"/>
/// </example>
public void SyncLayers()
{
if (m_RuntimeRigLayers == null)
return;
syncSceneToStreamLayer.Update(m_RuntimeRigLayers);
for (int i = 0, count = m_RuntimeRigLayers.Length; i < count; ++i)
{
if (m_RuntimeRigLayers[i].IsValid() && m_RuntimeRigLayers[i].active)
m_RuntimeRigLayers[i].Update();
}
}
/// <summary>
/// Builds the RigBuilder PlayableGraph.
/// </summary>
/// <returns>Returns true if the RigBuilder has created a valid PlayableGraph. Returns false otherwise.</returns>
public bool Build()
{
if (m_IsInPreview)
return false;
Clear();
var animator = GetComponent<Animator>();
if (animator == null || layers.Count == 0)
return false;
// Make a copy of the layers list.
m_RuntimeRigLayers = layers.ToArray();
graph = RigBuilderUtils.BuildPlayableGraph(animator, m_RuntimeRigLayers, syncSceneToStreamLayer);
if (!graph.IsValid())
return false;
graph.Play();
return true;
}
/// <summary>
/// Builds the RigBuilder playable nodes in an external PlayableGraph.
/// </summary>
/// <param name="graph">Destination PlayableGraph.</param>
/// <returns>Returns true if the RigBuilder has created Playable nodes. Returns false otherwise.</returns>
public bool Build(PlayableGraph graph)
{
if (m_IsInPreview)
return false;
Clear();
var animator = GetComponent<Animator>();
if (animator == null || layers.Count == 0)
return false;
// Make a copy of the layers list.
m_RuntimeRigLayers = layers.ToArray();
RigBuilderUtils.BuildPlayableGraph(graph, animator, m_RuntimeRigLayers, syncSceneToStreamLayer);
return true;
}
/// <summary>
/// Destroys the RigBuilder PlayableGraph and frees associated RigLayers memory.
/// </summary>
public void Clear()
{
if (m_IsInPreview)
return;
if (graph.IsValid())
graph.Destroy();
if (m_RuntimeRigLayers != null)
{
foreach (var layer in m_RuntimeRigLayers)
layer.Reset();
m_RuntimeRigLayers = null;
}
syncSceneToStreamLayer.Reset();
}
//
// IAnimationWindowPreview methods implementation
//
/// <summary>Notification callback when the animation previewer starts previewing an AnimationClip.</summary>
/// <remarks>This is called by the Animation Window or the Timeline Editor.</remarks>
public void StartPreview()
{
m_IsInPreview = true;
if (!enabled)
return;
// Make a copy of the layer list if it doesn't already exist.
if (m_RuntimeRigLayers == null)
m_RuntimeRigLayers = layers.ToArray();
var animator = GetComponent<Animator>();
if (animator != null)
{
foreach (var layer in m_RuntimeRigLayers)
{
layer.Initialize(animator);
}
}
}
/// <summary>Notification callback when the animation previewer stops previewing an AnimationClip.</summary>
/// <remarks>This is called by the Animation Window or the Timeline Editor.</remarks>
public void StopPreview()
{
m_IsInPreview = false;
if (!enabled)
return;
if (Application.isPlaying)
return;
Clear();
}
/// <summary>Notification callback when the animation previewer updates its PlayableGraph before sampling an AnimationClip.</summary>
/// <remarks>This is called by the Animation Window or the Timeline Editor.</remarks>
/// <param name="graph">The animation previewer PlayableGraph</param>
public void UpdatePreviewGraph(PlayableGraph graph)
{
if (!enabled)
return;
if (!graph.IsValid() || m_RuntimeRigLayers == null)
return;
syncSceneToStreamLayer.Update(m_RuntimeRigLayers);
foreach (var layer in m_RuntimeRigLayers)
{
if (layer.IsValid() && layer.active)
layer.Update();
}
}
/// <summary>
/// Appends custom Playable nodes to the animation previewer PlayableGraph.
/// </summary>
/// <param name="graph">The animation previewer PlayableGraph</param>
/// <param name="inputPlayable">The current root of the PlayableGraph</param>
/// <returns></returns>
public Playable BuildPreviewGraph(PlayableGraph graph, Playable inputPlayable)
{
if (!enabled)
return inputPlayable;
if (m_RuntimeRigLayers == null)
StartPreview();
var animator = GetComponent<Animator>();
if (animator == null || m_RuntimeRigLayers == null || m_RuntimeRigLayers.Length == 0)
return inputPlayable;
var playableChains = RigBuilderUtils.BuildPlayables(animator, graph, m_RuntimeRigLayers, syncSceneToStreamLayer);
foreach(var chain in playableChains)
{
if (chain.playables == null || chain.playables.Length == 0)
continue;
chain.playables[0].AddInput(inputPlayable, 0, 1);
inputPlayable = chain.playables[chain.playables.Length - 1];
}
return inputPlayable;
}
#if UNITY_EDITOR
/// <inheritdoc />
public void AddEffector(Transform transform, RigEffectorData.Style style)
{
var effector = new RigEffectorData();
effector.Initialize(transform, style);
m_Effectors.Add(effector);
}
/// <inheritdoc />
public void RemoveEffector(Transform transform)
{
m_Effectors.RemoveAll((RigEffectorData data) => data.transform == transform);
}
/// <inheritdoc />
public bool ContainsEffector(Transform transform)
{
return m_Effectors.Exists((RigEffectorData data) => data.transform == transform);
}
#endif
/// <summary>
/// Returns a list of RigLayer associated to this RigBuilder.
/// </summary>
public List<RigLayer> layers
{
get
{
if (m_RigLayers == null)
m_RigLayers = new List<RigLayer>();
return m_RigLayers;
}
set => m_RigLayers = value;
}
private SyncSceneToStreamLayer syncSceneToStreamLayer
{
get
{
if (m_SyncSceneToStreamLayer == null)
m_SyncSceneToStreamLayer = new SyncSceneToStreamLayer();
return m_SyncSceneToStreamLayer;
}
set => m_SyncSceneToStreamLayer = value;
}
/// <summary>
/// Retrieves the PlayableGraph created by this RigBuilder.
/// </summary>
public PlayableGraph graph { get; private set; }
}
}

View File

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

View File

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using UnityEngine.Experimental.Animations;
using UnityEngine.Playables;
namespace UnityEngine.Animations.Rigging
{
internal static class RigBuilderUtils
{
public struct PlayableChain
{
public string name;
public Playable[] playables;
public bool IsValid() => playables != null && playables.Length > 0;
}
private static readonly ushort k_AnimationOutputPriority = 1000;
public static Playable[] BuildRigPlayables(PlayableGraph graph, IRigLayer layer)
{
if (layer == null || layer.jobs == null || layer.jobs.Length == 0)
return null;
var count = layer.jobs.Length;
var playables = new Playable[count];
for (int i = 0; i < count; ++i)
{
var binder = layer.constraints[i].binder;
playables[i] = binder.CreatePlayable(graph, layer.jobs[i]);
}
// Connect rig playables serially
for (int i = 1; i < count; ++i)
playables[i].AddInput(playables[i - 1], 0, 1);
return playables;
}
public static IEnumerable<PlayableChain> BuildPlayables(Animator animator, PlayableGraph graph, IList<IRigLayer> layers, SyncSceneToStreamLayer syncSceneToStreamLayer)
{
var playableChains = new PlayableChain[layers.Count + 1];
// Create all rig layers
int index = 1;
foreach (var layer in layers)
{
var chain = new PlayableChain();
chain.name = layer.name;
if (layer.Initialize(animator))
chain.playables = BuildRigPlayables(graph, layer);
playableChains[index++] = chain;
}
// Create sync to stream job with all rig references
if (syncSceneToStreamLayer.Initialize(animator, layers) && syncSceneToStreamLayer.IsValid())
{
var chain = new PlayableChain();
chain.name = "syncSceneToStream";
chain.playables = new Playable[1] {RigUtils.syncSceneToStreamBinder.CreatePlayable(graph, syncSceneToStreamLayer.job)};
playableChains[0] = chain;
}
return playableChains;
}
public static PlayableGraph BuildPlayableGraph(Animator animator, IList<IRigLayer> layers, SyncSceneToStreamLayer syncSceneToStreamLayer)
{
string graphName = animator.gameObject.transform.name + "_Rigs";
PlayableGraph graph = PlayableGraph.Create(graphName);
graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
BuildPlayableGraph(graph, animator, layers, syncSceneToStreamLayer);
return graph;
}
public static void BuildPlayableGraph(PlayableGraph graph, Animator animator, IList<IRigLayer> layers, SyncSceneToStreamLayer syncSceneToStreamLayer)
{
IEnumerable<PlayableChain> playableChains = BuildPlayables(animator, graph, layers, syncSceneToStreamLayer);
foreach(var chain in playableChains)
{
if (!chain.IsValid())
continue;
AnimationPlayableOutput output = AnimationPlayableOutput.Create(graph, String.Format("{0}-Output", chain.name), animator);
output.SetAnimationStreamSource(AnimationStreamSource.PreviousInputs);
output.SetSortingOrder(k_AnimationOutputPriority);
// Connect last rig playable to output
output.SetSourcePlayable(chain.playables[chain.playables.Length - 1]);
}
}
}
}

View File

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

View File

@@ -0,0 +1,103 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// This is the base class for rig constraints.
/// Inherit from this class to implement custom constraints.
/// </summary>
/// <typeparam name="TJob">The constraint job</typeparam>
/// <typeparam name="TData">The constraint data</typeparam>
/// <typeparam name="TBinder">The constraint job binder</typeparam>
public class RigConstraint<TJob, TData, TBinder> : MonoBehaviour, IRigConstraint
where TJob : struct, IWeightedAnimationJob
where TData : struct, IAnimationJobData
where TBinder : AnimationJobBinder<TJob, TData>, new()
{
/// <summary>
/// The constraint weight parameter.
/// </summary>
[SerializeField, Range(0f, 1f)]
protected float m_Weight = 1f;
/// <summary>
/// The constraint data.
/// </summary>
[SerializeField, ExpandChildren]
protected TData m_Data;
static readonly TBinder s_Binder = new TBinder();
/// <summary>
/// Resets constraint data to default values.
/// </summary>
public void Reset()
{
m_Weight = 1f;
m_Data.SetDefaultValues();
}
/// <summary>
/// Retrieves the constraint valid state.
/// </summary>
/// <returns>Returns true if constraint data can be successfully evaluated. Returns false otherwise.</returns>
public bool IsValid() => m_Data.IsValid();
/// <summary>
/// This function is called when the script is loaded or a value is changed in the Inspector (Called in the editor only).
/// You can use this to ensure that when you modify data in an editor, that data stays within a certain range.
/// </summary>
protected virtual void OnValidate() => m_Weight = Mathf.Clamp01(m_Weight);
/// <summary>
/// The data container for the constraint.
/// </summary>
public ref TData data => ref m_Data;
/// <summary>
/// The constraint weight. This is a value in between 0 and 1.
/// </summary>
public float weight { get => m_Weight; set => m_Weight = Mathf.Clamp01(value); }
/// <summary>
/// Creates the animation job for this constraint.
/// </summary>
/// <param name="animator">The animated hierarchy Animator component</param>
/// <returns>Returns the newly instantiated job.</returns>
public IAnimationJob CreateJob(Animator animator)
{
TJob job = s_Binder.Create(animator, ref m_Data, this);
// Bind constraint job weight property
job.jobWeight = FloatProperty.BindCustom(
animator,
ConstraintsUtils.ConstructCustomPropertyName(this, ConstraintProperties.s_Weight)
);
return job;
}
/// <summary>
/// Frees the specified job memory.
/// </summary>
/// <param name="job">The job to destroy.</param>
public void DestroyJob(IAnimationJob job) => s_Binder.Destroy((TJob)job);
/// <summary>
/// Updates the specified job data.
/// </summary>
/// <param name="job">The job to update.</param>
public void UpdateJob(IAnimationJob job) => s_Binder.Update((TJob)job, ref m_Data);
/// <summary>
/// The job binder for the constraint.
/// </summary>
IAnimationJobBinder IRigConstraint.binder => s_Binder;
/// <summary>
/// The data container for the constraint.
/// </summary>
IAnimationJobData IRigConstraint.data => m_Data;
/// <summary>
/// The component for the constraint.
/// </summary>
Component IRigConstraint.component => (Component)this;
}
}

View File

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

View File

@@ -0,0 +1,104 @@
using System;
using UnityEngine.Serialization;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// The RigLayer is used by the RigBuilder to control in which order rigs will be
/// evaluated and whether they are active or not.
/// </summary>
[Serializable]
public class RigLayer : IRigLayer
{
[SerializeField][FormerlySerializedAs("rig")] private Rig m_Rig;
[SerializeField][FormerlySerializedAs("active")] private bool m_Active = true;
private IRigConstraint[] m_Constraints;
private IAnimationJob[] m_Jobs;
/// <summary>The Rig associated to the RigLayer</summary>
public Rig rig { get => m_Rig; private set => m_Rig = value; }
/// <summary>The active state. True if the RigLayer is active, false otherwise.</summary>
public bool active { get => m_Active; set => m_Active = value; }
/// <summary>The RigLayer name.</summary>
public string name { get => (rig != null ? rig.gameObject.name : "no-name"); }
/// <summary>The list of constraints associated with the RigLayer.</summary>
public IRigConstraint[] constraints { get => isInitialized ? m_Constraints : null; }
/// <summary>The list of jobs built from constraints associated with the RigLayer.</summary>
public IAnimationJob[] jobs { get => isInitialized ? m_Jobs : null; }
/// <summary>Returns true if RigLayer was initialized or false otherwise.</summary>
/// <seealso cref="RigLayer.Initialize"/>
public bool isInitialized { get; private set; }
/// <summary>
/// Constructor.
/// </summary>
/// <param name="rig">The rig represented by this rig layer.</param>
/// <param name="active">The active state of the rig layer.</param>
public RigLayer(Rig rig, bool active = true)
{
this.rig = rig;
this.active = active;
}
/// <summary>
/// Initializes the RigLayer. This will retrieve the constraints associated with the Rig
/// and create the animation jobs required by the PlayableGraph.
/// </summary>
/// <param name="animator">The Animator used to animate the RigLayer constraints.</param>
/// <returns>True if RigLayer was initialized properly, false otherwise.</returns>
public bool Initialize(Animator animator)
{
if (isInitialized)
return true;
if (rig != null)
{
m_Constraints = RigUtils.GetConstraints(rig);
if (m_Constraints == null || m_Constraints.Length == 0)
return false;
m_Jobs = RigUtils.CreateAnimationJobs(animator, m_Constraints);
return (isInitialized = true);
}
return false;
}
/// <summary>
/// Updates the RigLayer jobs. This is called during the Update loop before
/// the Animator evaluates the PlayableGraph.
/// </summary>
public void Update()
{
if (!isInitialized)
return;
for (int i = 0, count = m_Constraints.Length; i < count; ++i)
m_Constraints[i].UpdateJob(m_Jobs[i]);
}
/// <summary>
/// Resets the RigLayer. This will destroy the animation jobs and
/// free up memory.
/// </summary>
public void Reset()
{
if (!isInitialized)
return;
RigUtils.DestroyAnimationJobs(m_Constraints, m_Jobs);
m_Constraints = null;
m_Jobs = null;
isInitialized = false;
}
/// <summary>
/// Queries whether the RigLayer is valid.
/// </summary>
/// <returns>True if RigLayer is valid, false otherwise.</returns>
public bool IsValid() => rig != null && isInitialized;
}
}

View File

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

View File

@@ -0,0 +1,11 @@
namespace UnityEngine.Animations.Rigging
{
/// <summary>
///
/// </summary>
[DisallowMultipleComponent, AddComponentMenu("Animation Rigging/Setup/Rig Transform")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.animation.rigging@1.3/manual/RiggingWorkflow.html#rig-transform")]
public class RigTransform : MonoBehaviour
{
}
}

View File

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

View File

@@ -0,0 +1,334 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace UnityEngine.Animations.Rigging
{
static class RigUtils
{
internal static readonly Dictionary<Type, PropertyDescriptor> s_SupportedPropertyTypeToDescriptor = new Dictionary<Type, PropertyDescriptor>
{
{ typeof(float) , new PropertyDescriptor{ size = 1, type = PropertyType.Float } },
{ typeof(int) , new PropertyDescriptor{ size = 1, type = PropertyType.Int } },
{ typeof(bool) , new PropertyDescriptor{ size = 1, type = PropertyType.Bool } },
{ typeof(Vector2) , new PropertyDescriptor{ size = 2, type = PropertyType.Float } },
{ typeof(Vector3) , new PropertyDescriptor{ size = 3, type = PropertyType.Float } },
{ typeof(Vector4) , new PropertyDescriptor{ size = 4, type = PropertyType.Float } },
{ typeof(Quaternion) , new PropertyDescriptor{ size = 4, type = PropertyType.Float } },
{ typeof(Vector3Int) , new PropertyDescriptor{ size = 3, type = PropertyType.Int } },
{ typeof(Vector3Bool), new PropertyDescriptor{ size = 3, type = PropertyType.Bool } }
};
public static IRigConstraint[] GetConstraints(Rig rig)
{
IRigConstraint[] constraints = rig.GetComponentsInChildren<IRigConstraint>();
if (constraints.Length == 0)
return null;
List<IRigConstraint> tmp = new List<IRigConstraint>(constraints.Length);
foreach (var constraint in constraints)
{
if (constraint.IsValid())
tmp.Add(constraint);
}
return tmp.Count == 0 ? null : tmp.ToArray();
}
private static Transform[] GetSyncableRigTransforms(Animator animator)
{
RigTransform[] rigTransforms = animator.GetComponentsInChildren<RigTransform>();
if (rigTransforms.Length == 0)
return null;
Transform[] transforms = new Transform[rigTransforms.Length];
for (int i = 0; i < transforms.Length; ++i)
transforms[i] = rigTransforms[i].transform;
return transforms;
}
private static bool ExtractTransformType(
Animator animator,
FieldInfo field,
object data,
List<Transform> syncableTransforms
)
{
bool handled = true;
Type fieldType = field.FieldType;
if (fieldType == typeof(Transform))
{
var value = (Transform)field.GetValue(data);
if (value != null && value.IsChildOf(animator.avatarRoot))
syncableTransforms.Add(value);
}
else if (fieldType == typeof(Transform[]) || fieldType == typeof(List<Transform>))
{
var list = (IEnumerable<Transform>)field.GetValue(data);
foreach (var element in list)
if (element != null && element.IsChildOf(animator.avatarRoot))
syncableTransforms.Add(element);
}
else
handled = false;
return handled;
}
private static bool ExtractPropertyType(
FieldInfo field,
object data,
List<Property> syncableProperties,
string namePrefix = ""
)
{
if (!s_SupportedPropertyTypeToDescriptor.TryGetValue(field.FieldType, out PropertyDescriptor descriptor))
return false;
syncableProperties.Add(
new Property { name = ConstraintsUtils.ConstructConstraintDataPropertyName(namePrefix + field.Name), descriptor = descriptor }
);
return true;
}
private static bool ExtractWeightedTransforms(
Animator animator,
FieldInfo field,
object data,
List<Transform> syncableTransforms,
List<Property> syncableProperties)
{
bool handled = true;
Type fieldType = field.FieldType;
if (fieldType == typeof(WeightedTransform))
{
var value = ((WeightedTransform)field.GetValue(data)).transform;
if (value != null && value.IsChildOf(animator.avatarRoot))
syncableTransforms.Add(value);
syncableProperties.Add(
new Property { name = ConstraintsUtils.ConstructConstraintDataPropertyName(field.Name + ".weight"), descriptor = s_SupportedPropertyTypeToDescriptor[typeof(float)] }
);
}
else if (fieldType == typeof(WeightedTransformArray))
{
var list = (IEnumerable<WeightedTransform>)field.GetValue(data);
int index = 0;
foreach (var element in list)
{
if (element.transform != null && element.transform.IsChildOf(animator.avatarRoot))
syncableTransforms.Add(element.transform);
syncableProperties.Add(
new Property { name = ConstraintsUtils.ConstructConstraintDataPropertyName(field.Name + ".m_Item" + index + ".weight"), descriptor = s_SupportedPropertyTypeToDescriptor[typeof(float)] }
);
++index;
}
}
else
handled = false;
return handled;
}
private static bool ExtractNestedPropertyType(
Animator animator,
FieldInfo field,
object data,
List<Transform> syncableTransforms,
List<Property> syncableProperties,
string namePrefix = "")
{
Type fieldType = field.FieldType;
var fieldData = field.GetValue(data);
var fieldName = namePrefix + field.Name + ".";
// Only structs
if (!fieldType.IsValueType || fieldType.IsPrimitive)
return false;
var fields = fieldType.GetFields(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
).Where(info => info.GetCustomAttribute<SyncSceneToStreamAttribute>() != null);
foreach (var childField in fields)
{
if (ExtractTransformType(animator, childField, fieldData, syncableTransforms))
continue;
if (ExtractPropertyType(childField, fieldData, syncableProperties, fieldName))
continue;
if (ExtractNestedPropertyType(animator, childField, fieldData, syncableTransforms, syncableProperties, fieldName))
continue;
throw new NotSupportedException("Field type [" + field.FieldType + "] is not a supported syncable property type.");
}
return true;
}
private static void ExtractAllSyncableData(Animator animator, IList<IRigLayer> layers, out List<Transform> syncableTransforms, out List<SyncableProperties> syncableProperties)
{
syncableTransforms = new List<Transform>();
syncableProperties = new List<SyncableProperties>(layers.Count);
Dictionary<Type, FieldInfo[]> typeToSyncableFields = new Dictionary<Type, FieldInfo[]>();
foreach (var layer in layers)
{
if (!layer.IsValid())
continue;
var constraints = layer.constraints;
List<ConstraintProperties> allConstraintProperties = new List<ConstraintProperties>(constraints.Length);
foreach (var constraint in constraints)
{
var data = constraint.data;
var dataType = constraint.data.GetType();
if (!typeToSyncableFields.TryGetValue(dataType, out FieldInfo[] syncableFields))
{
FieldInfo[] allFields = dataType.GetFields(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
);
List<FieldInfo> filteredFields = new List<FieldInfo>(allFields.Length);
foreach (var field in allFields)
if (field.GetCustomAttribute<SyncSceneToStreamAttribute>() != null)
filteredFields.Add(field);
syncableFields = filteredFields.ToArray();
typeToSyncableFields[dataType] = syncableFields;
}
List<Property> properties = new List<Property>(syncableFields.Length);
foreach (var field in syncableFields)
{
if (ExtractWeightedTransforms(animator, field, data, syncableTransforms, properties))
continue;
if (ExtractTransformType(animator, field, data, syncableTransforms))
continue;
if (ExtractPropertyType(field, data, properties))
continue;
if (ExtractNestedPropertyType(animator, field, data, syncableTransforms, properties))
continue;
throw new NotSupportedException("Field type [" + field.FieldType + "] is not a supported syncable property type.");
}
allConstraintProperties.Add(
new ConstraintProperties {
component = constraint.component,
properties = properties.ToArray()
}
);
}
syncableProperties.Add(
new SyncableProperties {
rig = new RigProperties { component = layer.rig as Component },
constraints = allConstraintProperties.ToArray()
}
);
}
var extraTransforms = GetSyncableRigTransforms(animator);
if (extraTransforms != null)
syncableTransforms.AddRange(extraTransforms);
}
public static IAnimationJob[] CreateAnimationJobs(Animator animator, IRigConstraint[] constraints)
{
if (constraints == null || constraints.Length == 0)
return null;
IAnimationJob[] jobs = new IAnimationJob[constraints.Length];
for (int i = 0; i < constraints.Length; ++i)
jobs[i] = constraints[i].CreateJob(animator);
return jobs;
}
public static void DestroyAnimationJobs(IRigConstraint[] constraints, IAnimationJob[] jobs)
{
if (jobs == null || jobs.Length != constraints.Length)
return;
for (int i = 0; i < constraints.Length; ++i)
constraints[i].DestroyJob(jobs[i]);
}
private struct RigSyncSceneToStreamData : IAnimationJobData, IRigSyncSceneToStreamData
{
public RigSyncSceneToStreamData(Transform[] transforms, SyncableProperties[] properties, int rigCount)
{
if (transforms != null && transforms.Length > 0)
{
var unique = UniqueTransformIndices(transforms);
if (unique.Length != transforms.Length)
{
syncableTransforms = new Transform[unique.Length];
for (int i = 0; i < unique.Length; ++i)
syncableTransforms[i] = transforms[unique[i]];
}
else
syncableTransforms = transforms;
}
else
syncableTransforms = null;
syncableProperties = properties;
rigStates = rigCount > 0 ? new bool[rigCount] : null;
m_IsValid = !(((syncableTransforms == null || syncableTransforms.Length == 0) &&
(syncableProperties == null || syncableProperties.Length == 0) &&
rigStates == null));
}
static int[] UniqueTransformIndices(Transform[] transforms)
{
if (transforms == null || transforms.Length == 0)
return null;
HashSet<int> instanceIDs = new HashSet<int>();
List<int> unique = new List<int>(transforms.Length);
for (int i = 0; i < transforms.Length; ++i)
if (instanceIDs.Add(transforms[i].GetInstanceID()))
unique.Add(i);
return unique.ToArray();
}
public Transform[] syncableTransforms { get; private set; }
public SyncableProperties[] syncableProperties { get; private set; }
public bool[] rigStates { get; set; }
private readonly bool m_IsValid;
bool IAnimationJobData.IsValid() => m_IsValid;
void IAnimationJobData.SetDefaultValues()
{
syncableTransforms = null;
syncableProperties = null;
rigStates = null;
}
}
internal static IAnimationJobData CreateSyncSceneToStreamData(Animator animator, IList<IRigLayer> layers)
{
ExtractAllSyncableData(animator, layers, out List<Transform> syncableTransforms, out List<SyncableProperties> syncableProperties);
return new RigSyncSceneToStreamData(syncableTransforms.ToArray(), syncableProperties.ToArray(), layers.Count);
}
public static IAnimationJobBinder syncSceneToStreamBinder { get; } = new RigSyncSceneToStreamJobBinder<RigSyncSceneToStreamData>();
}
}

View File

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

View File

@@ -0,0 +1,65 @@
using System.Collections.Generic;
namespace UnityEngine.Animations.Rigging
{
class SyncSceneToStreamLayer
{
public bool Initialize(Animator animator, IList<IRigLayer> layers)
{
if (isInitialized)
return true;
m_RigIndices = new List<int>(layers.Count);
for (int i = 0; i < layers.Count; ++i)
{
if (!layers[i].IsValid())
continue;
m_RigIndices.Add(i);
}
m_Data = RigUtils.CreateSyncSceneToStreamData(animator, layers);
if (!m_Data.IsValid())
return false;
job = RigUtils.syncSceneToStreamBinder.Create(animator, m_Data);
return (isInitialized = true);
}
public void Update(IList<IRigLayer> layers)
{
if (!isInitialized || !m_Data.IsValid())
return;
IRigSyncSceneToStreamData syncData = (IRigSyncSceneToStreamData)m_Data;
for (int i = 0, count = m_RigIndices.Count; i < count; ++i)
syncData.rigStates[i] = layers[m_RigIndices[i]].active;
RigUtils.syncSceneToStreamBinder.Update(job, m_Data);
}
public void Reset()
{
if (!isInitialized)
return;
if (m_Data != null && m_Data.IsValid())
{
RigUtils.syncSceneToStreamBinder.Destroy(job);
m_Data = null;
}
isInitialized = false;
}
public bool IsValid() => job != null && m_Data != null;
public bool isInitialized { get; private set; }
public IAnimationJob job;
private IAnimationJobData m_Data;
private List<int> m_RigIndices;
}
}

View File

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

View File

@@ -0,0 +1,75 @@
using System;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// Provides an accessor to a Transform component reference.
/// </summary>
public interface ITransformProvider
{
/// <summary>
/// Reference to a Transform component.
/// </summary>
Transform transform { get; set; }
}
/// <summary>
/// Provides an access to a weight value.
/// </summary>
public interface IWeightProvider
{
/// <summary>
/// Weight. This is a number in between 0 and 1.
/// </summary>
float weight { get; set; }
}
/// <summary>
/// Tuple of a Reference to a Transform component and a weight number.
/// See also <seealso cref="WeightedTransformArray"/> and <seealso cref="WeightRangeAttribute"/>.
/// </summary>
[Serializable]
public struct WeightedTransform : ITransformProvider, IWeightProvider, IEquatable<WeightedTransform>
{
/// <summary>Reference to a Transform component.</summary>
public Transform transform;
/// <summary>Weight. This is a number be in between 0 and 1.</summary>
public float weight;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="transform">Reference to a Transform component.</param>
/// <param name="weight">Weight. This is a number in between 0 and 1.</param>
public WeightedTransform(Transform transform, float weight)
{
this.transform = transform;
this.weight = Mathf.Clamp01(weight);
}
/// <summary>
/// Returns a WeightedTransform object with an null Transform component reference and the specified weight.
/// </summary>
/// <param name="weight">Weight. This is a number in between 0 and 1.</param>
/// <returns>Returns a new WeightedTransform</returns>
public static WeightedTransform Default(float weight) => new WeightedTransform(null, weight);
/// <summary>
/// Compare two WeightedTransform objects for equality.
/// </summary>
/// <param name="other">A WeightedTransform object</param>
/// <returns>Returns true if both WeightedTransform have the same values. False otherwise.</returns>
public bool Equals(WeightedTransform other)
{
if (transform == other.transform && weight == other.weight)
return true;
return false;
}
/// <inheritdoc />
Transform ITransformProvider.transform { get => transform; set => transform = value; }
/// <inheritdoc />
float IWeightProvider.weight { get => weight; set => weight = Mathf.Clamp01(value); }
}
}

View File

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

View File

@@ -0,0 +1,454 @@
using System.Collections.Generic;
using System.Collections;
using System;
namespace UnityEngine.Animations.Rigging
{
/// <summary>
/// This struct defines a List of WeightedTransform.
/// WeightedTransformArray can be animated (as opposed to System.List and C# arrays) and is implemented
/// with a hard limit of eight WeightedTransform elements.
/// See also <seealso cref="WeightedTransform"/> and <seealso cref="WeightRangeAttribute"/>.
/// </summary>
[Serializable]
public struct WeightedTransformArray : IList<WeightedTransform>, IList
{
/// <summary>Maximum number of elements in WeightedTransformArray.</summary>
public static readonly int k_MaxLength = 8;
[SerializeField, NotKeyable] private int m_Length;
[SerializeField] private WeightedTransform m_Item0;
[SerializeField] private WeightedTransform m_Item1;
[SerializeField] private WeightedTransform m_Item2;
[SerializeField] private WeightedTransform m_Item3;
[SerializeField] private WeightedTransform m_Item4;
[SerializeField] private WeightedTransform m_Item5;
[SerializeField] private WeightedTransform m_Item6;
[SerializeField] private WeightedTransform m_Item7;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="size">Size of the array. This will clamped to be a number in between 0 and k_MaxLength.</param>
/// <seealso cref="WeightedTransformArray.k_MaxLength"/>
public WeightedTransformArray(int size)
{
m_Length = ClampSize(size);
m_Item0 = new WeightedTransform();
m_Item1 = new WeightedTransform();
m_Item2 = new WeightedTransform();
m_Item3 = new WeightedTransform();
m_Item4 = new WeightedTransform();
m_Item5 = new WeightedTransform();
m_Item6 = new WeightedTransform();
m_Item7 = new WeightedTransform();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>An IEnumerator object that can be used to iterate through the collection.</returns>
public IEnumerator<WeightedTransform> GetEnumerator()
{
return new Enumerator(ref this);
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>An IEnumerator object that can be used to iterate through the collection.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return new Enumerator(ref this);
}
/// <summary>
/// Adds an item to the WeightedTransformArray.
/// </summary>
/// <param name="value">The object to add to the WeightedTransformArray.</param>
/// <returns>The position into which the new element was inserted, or -1 to indicate that the item was not inserted into the collection.</returns>
int IList.Add(object value)
{
Add((WeightedTransform)value);
return m_Length - 1;
}
/// <summary>
/// Adds an item to the WeightedTransformArray.
/// </summary>
/// <param name="value">The WeightedTransform to add to the WeightedTransformArray.</param>
public void Add(WeightedTransform value)
{
if (m_Length >= k_MaxLength)
throw new ArgumentException($"This array cannot have more than '{k_MaxLength}' items.");
Set(m_Length, value);
++m_Length;
}
/// <summary>
/// Removes all items from the WeightedTransformArray.
/// </summary>
public void Clear()
{
m_Length = 0;
}
/// <summary>
/// Determines the index of a specific item in the WeightedTransformArray.
/// </summary>
/// <param name="value">The object to locate in the WeightedTransformArray.</param>
/// <returns>The index of value if found in the list; otherwise, -1.</returns>
int IList.IndexOf(object value) => IndexOf((WeightedTransform)value);
/// <summary>
/// Determines the index of a specific item in the WeightedTransformArray.
/// </summary>
/// <param name="value">The WeightedTransform to locate in the WeightedTransformArray.</param>
/// <returns>The index of value if found in the list; otherwise, -1.</returns>
public int IndexOf(WeightedTransform value)
{
for (int i = 0; i < m_Length; ++i)
{
if (Get(i).Equals(value))
return i;
}
return -1;
}
/// <summary>
/// Determines whether the WeightedTransformArray contains a specific value.
/// </summary>
/// <param name="value">The object to locate in the WeightedTransformArray.</param>
/// <returns>true if the Object is found in the WeightedTransformArray; otherwise, false.</returns>
bool IList.Contains(object value) => Contains((WeightedTransform)value);
/// <summary>
/// Determines whether the WeightedTransformArray contains a specific value.
/// </summary>
/// <param name="value">The WeightedTransform to locate in the WeightedTransformArray.</param>
/// <returns>true if the Object is found in the WeightedTransformArray; otherwise, false.</returns>
public bool Contains(WeightedTransform value)
{
for (int i = 0; i < m_Length; ++i)
{
if (Get(i).Equals(value))
return true;
}
return false;
}
/// <summary>
/// Copies the elements of the WeightedTransform to an Array, starting at a particular Array index.
/// </summary>
/// <param name="array">The one-dimensional Array that is the destination of the elements copied from WeightedTransform. The Array must have zero-based indexing.</param>
/// <param name="arrayIndex">The zero-based index in array at which copying begins.</param>
void ICollection.CopyTo(Array array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException("The array cannot be null.");
if (arrayIndex < 0)
throw new ArgumentOutOfRangeException("The starting array index cannot be negative.");
if (Count > array.Length - arrayIndex + 1)
throw new ArgumentException("The destination array has fewer elements than the collection.");
for (int i = 0; i < m_Length; i++)
{
array.SetValue(Get(i), i + arrayIndex);
}
}
/// <summary>
/// Copies the elements of the WeightedTransform to an Array, starting at a particular Array index.
/// </summary>
/// <param name="array">The one-dimensional Array that is the destination of the elements copied from WeightedTransform. The Array must have zero-based indexing.</param>
/// <param name="arrayIndex">The zero-based index in array at which copying begins.</param>
public void CopyTo(WeightedTransform[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException("The array cannot be null.");
if (arrayIndex < 0)
throw new ArgumentOutOfRangeException("The starting array index cannot be negative.");
if (Count > array.Length - arrayIndex + 1)
throw new ArgumentException("The destination array has fewer elements than the collection.");
for (int i = 0; i < m_Length; i++)
{
array[i + arrayIndex] = Get(i);
}
}
/// <summary>
/// Removes the first occurrence of a specific object from the WeightedTransformArray.
/// </summary>
/// <param name="value">The object to remove from the WeightedTransformArray.</param>
void IList.Remove(object value) { Remove((WeightedTransform)value); }
/// <summary>
/// Removes the first occurrence of a specific WeightedTransform from the WeightedTransformArray.
/// </summary>
/// <param name="value">The WeightedTransform to remove from the WeightedTransformArray.</param>
/// <returns>True if value was removed from the array, false otherwise.</returns>
public bool Remove(WeightedTransform value)
{
for (int i = 0; i < m_Length; ++i)
{
if (Get(i).Equals(value))
{
for (; i < m_Length - 1; ++i)
{
Set(i, Get(i + 1));
}
--m_Length;
return true;
}
}
return false;
}
/// <summary>
/// Removes the WeightedTransformArray item at the specified index.
/// </summary>
/// <param name="index">The zero-based index of the item to remove.</param>
public void RemoveAt(int index)
{
CheckOutOfRangeIndex(index);
for (int i = index; i < m_Length - 1; ++i)
{
Set(i, Get(i + 1));
}
--m_Length;
}
/// <summary>
/// Inserts an item to the WeightedTransformArray at the specified index.
/// </summary>
/// <param name="index">The zero-based index at which value should be inserted.</param>
/// <param name="value">The object to insert into the WeightedTransformArray.</param>
void IList.Insert(int index, object value) => Insert(index, (WeightedTransform)value);
/// <summary>
/// Inserts an item to the WeightedTransformArray at the specified index.
/// </summary>
/// <param name="index">The zero-based index at which value should be inserted.</param>
/// <param name="value">The WeightedTransform to insert into the WeightedTransformArray.</param>
public void Insert(int index, WeightedTransform value)
{
if (m_Length >= k_MaxLength)
throw new ArgumentException($"This array cannot have more than '{k_MaxLength}' items.");
CheckOutOfRangeIndex(index);
if (index >= m_Length)
{
Add(value);
return;
}
for (int i = m_Length; i > index; --i)
{
Set(i, Get(i - 1));
}
Set(index, value);
++m_Length;
}
/// <summary>
/// Clamps specified value in between 0 and k_MaxLength.
/// </summary>
/// <param name="size">Size value.</param>
/// <returns>Value in between 0 and k_MaxLength.</returns>
/// <seealso cref="WeightedTransformArray.k_MaxLength"/>
private static int ClampSize(int size)
{
return Mathf.Clamp(size, 0, k_MaxLength);
}
/// <summary>
/// Checks whether specified index value in within bounds.
/// </summary>
/// <param name="index">Index value.</param>
/// <exception cref="IndexOutOfRangeException">Index value is not between 0 and k_MaxLength.</exception>
/// <seealso cref="WeightedTransformArray.k_MaxLength"/>
private void CheckOutOfRangeIndex(int index)
{
if (index < 0 || index >= k_MaxLength)
throw new IndexOutOfRangeException($"Index {index} is out of range of '{m_Length}' Length.");
}
/// <summary>
/// Retrieves a WeightedTransform at specified index.
/// </summary>
/// <param name="index">Index value.</param>
/// <returns>The WeightedTransform value at specified index.</returns>
private WeightedTransform Get(int index)
{
CheckOutOfRangeIndex(index);
switch(index)
{
case 0: return m_Item0;
case 1: return m_Item1;
case 2: return m_Item2;
case 3: return m_Item3;
case 4: return m_Item4;
case 5: return m_Item5;
case 6: return m_Item6;
case 7: return m_Item7;
}
// Shouldn't happen.
return m_Item0;
}
/// <summary>
/// Sets a WeightedTransform at specified index.
/// </summary>
/// <param name="index">Index value.</param>
/// <param name="value">The WeightedTransform value to set.</param>
private void Set(int index, WeightedTransform value)
{
CheckOutOfRangeIndex(index);
switch(index)
{
case 0: m_Item0 = value; break;
case 1: m_Item1 = value; break;
case 2: m_Item2 = value; break;
case 3: m_Item3 = value; break;
case 4: m_Item4 = value; break;
case 5: m_Item5 = value; break;
case 6: m_Item6 = value; break;
case 7: m_Item7 = value; break;
}
}
/// <summary>
/// Sets a weight on a WeightedTransform at specified index.
/// </summary>
/// <param name="index">Index value.</param>
/// <param name="weight">The weight value to set.</param>
public void SetWeight(int index, float weight)
{
var weightedTransform = Get(index);
weightedTransform.weight = weight;
Set(index, weightedTransform);
}
/// <summary>
/// Retrieves a weight on a WeightedTransform at specified index.
/// </summary>
/// <param name="index">Index value.</param>
/// <returns>The weight value at specified index.</returns>
public float GetWeight(int index)
{
return Get(index).weight;
}
/// <summary>
/// Sets the Transform reference on a WeightedTransform at specified index.
/// </summary>
/// <param name="index">Index value.</param>
/// <param name="transform">The Transform reference to set.</param>
public void SetTransform(int index, Transform transform)
{
var weightedTransform = Get(index);
weightedTransform.transform = transform;
Set(index, weightedTransform);
}
/// <summary>
/// Retrieves a Transform reference on a WeightedTransform at specified index.
/// </summary>
/// <param name="index">Index value.</param>
/// <returns>The Transform reference at specified index.</returns>
public Transform GetTransform(int index)
{
return Get(index).transform;
}
/// <summary>
/// Method to call from a provider's OnValidate() callback to ensure all weight values are within the valid range.
/// See also <seealso cref="WeightRangeAttribute"/>.
/// </summary>
/// <param name="array">WeightedTransformArray to adjust.</param>
/// <param name="min">Minimum value to clamp array values with.</param>
/// <param name="max">Maximum value to clamp array values with.</param>
public static void OnValidate(ref WeightedTransformArray array, float min = 0f, float max = 1f)
{
for (var i = 0; i < k_MaxLength; ++i)
array.SetWeight(i, Mathf.Clamp(array.GetWeight(i), min, max));
}
/// <summary>
/// Gets or sets the element at the specified index.
/// </summary>
/// <param name="index">The zero-based index of the element to get or set.</param>
object IList.this[int index] { get => (object)Get(index); set => Set(index, (WeightedTransform)value); }
/// <summary>
/// Gets or sets the WeightedTransform at the specified index.
/// </summary>
/// <param name="index">The zero-based index of the WeightedTransform to get or set.</param>
public WeightedTransform this[int index] { get => Get(index); set => Set(index, value); }
/// <summary>The number of elements contained in the WeightedTransformArray.</summary>
public int Count { get => m_Length; }
/// <summary>
/// Retrieves whether WeightedTransformArray is read-only. Always false.
/// </summary>
public bool IsReadOnly { get => false; }
/// <summary>
/// Retrieves whether WeightedTransformArray has a fixed size. Always false.
/// </summary>
public bool IsFixedSize { get => false; }
bool ICollection.IsSynchronized { get => true; }
object ICollection.SyncRoot { get => null; }
[System.Serializable]
private struct Enumerator : IEnumerator<WeightedTransform>
{
private WeightedTransformArray m_Array;
private int m_Index;
public Enumerator(ref WeightedTransformArray array)
{
m_Array = array;
m_Index = -1;
}
public bool MoveNext()
{
m_Index++;
return (m_Index < m_Array.Count);
}
public void Reset()
{
m_Index = -1;
}
void IDisposable.Dispose() { }
public WeightedTransform Current => m_Array.Get(m_Index);
object IEnumerator.Current => Current;
}
}
}

View File

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

View File

@@ -0,0 +1,4 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Unity.Animation.Rigging.Editor")]
[assembly: InternalsVisibleTo("Unity.Animation.Rigging.Tests")]
[assembly: InternalsVisibleTo("Unity.Animation.Rigging.EditorTests")]

View File

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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 53534b516478036469d430efd7bbc497
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,4 @@
namespace UnityEngine.Animations.Rigging
{
sealed class ExpandChildrenAttribute : PropertyAttribute {}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8bce5d2428eb4d4aa4115d557baa49aa
timeCreated: 1607627626

Some files were not shown because too many files have changed in this diff Show More