using Unity.Collections;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Animations.Rigging;
namespace UnityEditor.Animations.Rigging
{
///
/// The MultiRotation inverse constraint job.
///
[Unity.Burst.BurstCompile]
public struct MultiRotationInverseConstraintJob : IWeightedAnimationJob
{
const float k_Epsilon = 1e-5f;
/// The Transform handle for the constrained object Transform.
public ReadOnlyTransformHandle driven;
/// The Transform handle for the constrained object parent Transform.
public ReadOnlyTransformHandle drivenParent;
/// The post-rotation offset applied to the constrained object.
public Vector3Property drivenOffset;
/// List of Transform handles for the source objects.
public NativeArray sourceTransforms;
/// List of weights for the source objects.
public NativeArray sourceWeights;
/// List of offsets to apply to source rotations if maintainOffset is enabled.
public NativeArray sourceOffsets;
/// Buffer used to store weights during job execution.
public NativeArray weightBuffer;
///
public FloatProperty jobWeight { get; set; }
///
/// Defines what to do when processing the root motion.
///
/// The animation stream to work on.
public void ProcessRootMotion(AnimationStream stream) { }
///
/// Defines what to do when processing the animation.
///
/// The animation stream to work on.
public void ProcessAnimation(AnimationStream stream)
{
jobWeight.Set(stream, 1f);
var lRot = driven.GetLocalRotation(stream);
var offset = drivenOffset.Get(stream);
if (Vector3.Dot(offset, offset) > 0f)
lRot *= Quaternion.Inverse(Quaternion.Euler(offset));
var wRot = lRot;
if (drivenParent.IsValid(stream))
{
wRot = drivenParent.GetRotation(stream) * wRot;
}
for (int i = 0; i < sourceTransforms.Length; ++i)
{
sourceWeights[i].SetFloat(stream, 1f);
ReadWriteTransformHandle sourceTransform = sourceTransforms[i];
sourceTransform.SetRotation(stream, wRot * sourceOffsets[i]);
// Required to update handles with binding info.
sourceTransforms[i] = sourceTransform;
}
}
}
///
/// The MultiRotation inverse constraint job binder.
///
/// The constraint data type
public class MultiRotationInverseConstraintJobBinder : AnimationJobBinder
where T : struct, IAnimationJobData, IMultiRotationConstraintData
{
///
public override MultiRotationInverseConstraintJob Create(Animator animator, ref T data, Component component)
{
var job = new MultiRotationInverseConstraintJob();
job.driven = ReadOnlyTransformHandle.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.BindReadWriteTransforms(animator, component, sourceObjects, out job.sourceTransforms);
WeightedTransformArrayBinder.BindWeights(animator, component, sourceObjects, data.sourceObjectsProperty, out job.sourceWeights);
job.sourceOffsets = new NativeArray(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
job.weightBuffer = new NativeArray(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
Quaternion drivenRotInv = Quaternion.Inverse(data.constrainedObject.rotation);
for (int i = 0; i < sourceObjects.Count; ++i)
{
job.sourceOffsets[i] = data.maintainOffset ?
(drivenRotInv * sourceObjects[i].transform.rotation) : Quaternion.identity;
}
return job;
}
///
public override void Destroy(MultiRotationInverseConstraintJob job)
{
job.sourceTransforms.Dispose();
job.sourceWeights.Dispose();
job.sourceOffsets.Dispose();
job.weightBuffer.Dispose();
}
}
}