/// <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);
        }
        /// <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);
            }
        }
    public void MultiPositionConstraint_TransferMotionToConstraint(
        [Values(false, true)] bool applySourceOffsets,
        [Values(false, true)] bool applyDrivenOffset,
        [Values(AxesMask.X, AxesMask.XY, AxesMask.XYZ)] AxesMask axesMask)
    {
        var data       = MultiPositionConstraintTests.SetupConstraintRig();
        var constraint = data.constraint;

        var rootGO     = data.rigData.rootGO;
        var rigBuilder = rootGO.GetComponent <RigBuilder>();

        var constrainedObject = constraint.data.constrainedObject;
        var sources           = constraint.data.sourceObjects;

        var vectorMask = new Vector3(
            System.Convert.ToSingle(RuntimeRiggingEditorTestFixture.TestXAxis(axesMask)),
            System.Convert.ToSingle(RuntimeRiggingEditorTestFixture.TestYAxis(axesMask)),
            System.Convert.ToSingle(RuntimeRiggingEditorTestFixture.TestZAxis(axesMask))
            );

        constraint.data.maintainOffset   = applySourceOffsets;
        constraint.data.offset           = applyDrivenOffset ? AnimationRuntimeUtils.Select(Vector3.zero, new Vector3(1f, 2f, 3f), vectorMask) : Vector3.zero;
        constraint.data.constrainedXAxis = RuntimeRiggingEditorTestFixture.TestXAxis(axesMask);
        constraint.data.constrainedYAxis = RuntimeRiggingEditorTestFixture.TestYAxis(axesMask);
        constraint.data.constrainedZAxis = RuntimeRiggingEditorTestFixture.TestZAxis(axesMask);

        var src0 = sources[0].transform;
        var src1 = sources[1].transform;

        src0.transform.position += Vector3.right;
        src1.transform.position += Vector3.up;

        var clip = new AnimationClip();

        var constraintPath        = AnimationUtility.CalculateTransformPath(constraint.transform, rootGO.transform);
        var constrainedObjectPath = AnimationUtility.CalculateTransformPath(constraint.data.constrainedObject, rootGO.transform);

        var weight0Attribute = ((IMultiPositionConstraintData)constraint.data).sourceObjectsProperty + ".m_Item0.weight";
        var weight1Attribute = ((IMultiPositionConstraintData)constraint.data).sourceObjectsProperty + ".m_Item1.weight";

        AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(constraintPath, typeof(MultiPositionConstraint), weight0Attribute), AnimationCurve.Constant(0f, 1f, 0.5f));
        AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(constraintPath, typeof(MultiPositionConstraint), weight1Attribute), AnimationCurve.Constant(0f, 1f, 0.5f));

        AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(constrainedObjectPath, typeof(Transform), "m_LocalPosition.x"), AnimationCurve.Linear(0f, -0.5f, 1f, 0.5f));
        AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(constrainedObjectPath, typeof(Transform), "m_LocalPosition.y"), AnimationCurve.Linear(0f, -1.5f, 1f, 1.5f));
        AnimationUtility.SetEditorCurve(clip, EditorCurveBinding.FloatCurve(constrainedObjectPath, typeof(Transform), "m_LocalPosition.z"), AnimationCurve.Linear(0f, -2.5f, 1f, 2.5f));

        RuntimeRiggingEditorTestFixture.TestTransferMotionToConstraint(constraint, rigBuilder, clip, new Transform[] { constrainedObject }, CompareFlags.TR);
    }
        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>
        /// 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);
            }
        }
    public void ProcessAnimation(AnimationStream stream)
    {
        float w = jobWeight.Get(stream);

        var sliderPos = Slider.GetLocalPosition(stream);
        var t         = Mathf.Clamp01(sliderPos.y);

        Slider.SetLocalPosition(stream, new Vector3(0, t, 0));

        if (w > 0f)
        {
            var rootRot = Root.GetRotation(stream);
            var midRot  = Mid.GetRotation(stream);
            var tipRot  = Tip.GetRotation(stream);

            var rootRotFK = Quaternion.Lerp(rootRot, FK_Root.GetRotation(stream), w);
            var midRotFK  = Quaternion.Lerp(midRot, FK_Mid.GetRotation(stream), w);
            var tipRotFK  = tipRot;

            AnimationRuntimeUtils.SolveTwoBoneIK(
                stream, Root, Mid, Tip, IK_Target, IK_Hint,
                posWeight: 1f * w,
                rotWeight: 0 * w,
                hintWeight: 1f * w,
                limbLengths: LinkLengths,
                targetOffset: AffineTransform.identity
                );
            var rootRotIK = Root.GetRotation(stream);
            var midRotIK  = Mid.GetRotation(stream);
            var tipRotIK  = Tip.GetRotation(stream);

            Root.SetRotation(stream, Quaternion.Lerp(rootRotFK, rootRotIK, t));
            Mid.SetRotation(stream, Quaternion.Lerp(midRotFK, midRotIK, t));
            Tip.SetRotation(stream, Quaternion.Lerp(tipRotFK, tipRotIK, t));
        }
    }
        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);
            }
        }