namespace UnityEngine.Animations.Rigging { /// /// The Blend constraint job. /// [Unity.Burst.BurstCompile] public struct BlendConstraintJob : IWeightedAnimationJob { private const int k_BlendTranslationMask = 1 << 0; private const int k_BlendRotationMask = 1 << 1; /// The Transform handle for the constrained object Transform. public ReadWriteTransformHandle driven; /// The Transform handle for sourceA Transform. public ReadOnlyTransformHandle sourceA; /// The Transform handle for sourceB Transform. public ReadOnlyTransformHandle sourceB; /// TR offset to apply to sourceA if maintainOffset is enabled. public AffineTransform sourceAOffset; /// TR offset to apply to sourceB if maintainOffset is enabled. public AffineTransform sourceBOffset; /// Toggles whether to blend position in the job. public BoolProperty blendPosition; /// Toggles whether to blend rotation in the job. public BoolProperty blendRotation; /// /// 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. /// public FloatProperty positionWeight; /// /// 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. /// public FloatProperty rotationWeight; /// 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) { 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); } } /// /// This interface defines the data mapping for the Blend constraint. /// public interface IBlendConstraintData { /// The Transform affected by the two source Transforms. Transform constrainedObject { get; } /// First Transform in blend. Transform sourceObjectA { get; } /// Second Transform in blend. Transform sourceObjectB { get; } /// This is used to maintain the current position offset from the constrained GameObject to the source GameObjects. bool maintainPositionOffsets { get; } /// This is used to maintain the current rotation offset from the constrained GameObject to the source GameObjects. bool maintainRotationOffsets { get; } /// The path to the blend position property in the constraint component. string blendPositionBoolProperty { get; } /// The path to the blend rotation property in the constraint component. string blendRotationBoolProperty { get; } /// The path to the position weight property in the constraint component. string positionWeightFloatProperty { get; } /// The path to the rotation weight property in the constraint component. string rotationWeightFloatProperty { get; } } /// /// The Blend constraint job binder. /// /// The constraint data type public class BlendConstraintJobBinder : AnimationJobBinder where T : struct, IAnimationJobData, IBlendConstraintData { /// 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; } /// public override void Destroy(BlendConstraintJob job) { } } }