public static void RestoreDefaultPose(Animator animator, AnimationClip defaultPoseClip)
 {
     using (var graph = new EvaluationGraph(animator, defaultPoseClip))
     {
         graph.Evaluate(0f);
     }
 }
    public static void TestTransferMotionToConstraint <T>(T constraint, RigBuilder rigBuilder, AnimationClip clip, IList <Transform> targetTransforms, CompareFlags flags)
        where T : MonoBehaviour, IRigConstraint
    {
        Animator animator = rigBuilder.GetComponent <Animator>();

        int   numberOfFrames = 60;
        float dt             = 1f / numberOfFrames;

        var defaultPoseClip = CreateDefaultPose(rigBuilder.gameObject);

#if DEBUG_BAKE_TO_CONSTRAINT
        AssetDatabase.CreateAsset(clip, "Assets/bakeToConstraintBefore.anim");
        clip = UnityEngine.Object.Instantiate(clip) as AnimationClip;
#endif

        // Evaluate clip without constraint and take snapshots.
        var translationsBeforeBaking = new Vector3[targetTransforms.Count, numberOfFrames + 1];
        var rotationsBeforeBaking    = new Quaternion[targetTransforms.Count, numberOfFrames + 1];

        using (var graph = new EvaluationGraph(rigBuilder.GetComponent <Animator>(), clip))
        {
            graph.Evaluate(0f);
            for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex)
            {
                translationsBeforeBaking[transformIndex, 0] = targetTransforms[transformIndex].position;
                rotationsBeforeBaking[transformIndex, 0]    = targetTransforms[transformIndex].rotation;
            }

            for (int frame = 1; frame <= numberOfFrames; ++frame)
            {
                graph.Evaluate(dt);
                for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex)
                {
                    translationsBeforeBaking[transformIndex, frame] = targetTransforms[transformIndex].position;
                    rotationsBeforeBaking[transformIndex, frame]    = targetTransforms[transformIndex].rotation;
                }
            }
        }

        RestoreDefaultPose(animator, defaultPoseClip);

        // Bake and inverse solve to constraint.
        var bakeParameters = BakeUtils.FindBakeParameters(constraint);
        Assert.That(bakeParameters, Is.Not.Null);

        var bindings = bakeParameters.GetSourceCurveBindings(rigBuilder, constraint);

        AnimationMode.StartAnimationMode();
        BakeUtils.BakeToConstraint(constraint, clip, defaultPoseClip, bindings, k_DefaultCurveFilterOptions);
        AnimationMode.StopAnimationMode();

#if DEBUG_BAKE_TO_CONSTRAINT
        AssetDatabase.CreateAsset(clip, "Assets/bakeToConstraintAfter.anim");
#endif

        RestoreDefaultPose(animator, defaultPoseClip);

        // Evaluate again with constraint active and take snapshots.
        var translationsAfterBaking = new Vector3[targetTransforms.Count, numberOfFrames + 1];
        var rotationsAfterBaking    = new Quaternion[targetTransforms.Count, numberOfFrames + 1];

        using (var graph = new EvaluationGraph(rigBuilder, clip))
        {
            graph.Evaluate(0f);
            for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex)
            {
                translationsAfterBaking[transformIndex, 0] = targetTransforms[transformIndex].position;
                rotationsAfterBaking[transformIndex, 0]    = targetTransforms[transformIndex].rotation;
            }

            for (int frame = 1; frame <= numberOfFrames; ++frame)
            {
                graph.Evaluate(dt);
                for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex)
                {
                    translationsAfterBaking[transformIndex, frame] = targetTransforms[transformIndex].position;
                    rotationsAfterBaking[transformIndex, frame]    = targetTransforms[transformIndex].rotation;
                }
            }
        }

        RestoreDefaultPose(animator, defaultPoseClip);

        if ((flags & CompareFlags.Rotation) != 0)
        {
            // Compare rotations
            var quaternionComparer = new RuntimeRiggingTestFixture.QuaternionEqualityComparer(k_RotationEpsilon);

            for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex)
            {
                for (int frame = 0; frame <= numberOfFrames; ++frame)
                {
                    Assert.That(rotationsAfterBaking[transformIndex, frame], Is.EqualTo(rotationsBeforeBaking[transformIndex, frame]).Using(quaternionComparer),
                                String.Format("Transform '{0}' rotation is set to {1} at frame {2}, but was expected to be {3}",
                                              targetTransforms[transformIndex].name, rotationsAfterBaking[transformIndex, frame].eulerAngles, frame, rotationsBeforeBaking[transformIndex, frame].eulerAngles));
                }
            }
        }

        if ((flags & CompareFlags.Translation) != 0)
        {
            // Compare translations
            var positionComparer = new RuntimeRiggingTestFixture.Vector3EqualityComparer(k_Epsilon);

            for (int transformIndex = 0; transformIndex < targetTransforms.Count; ++transformIndex)
            {
                for (int frame = 0; frame <= numberOfFrames; ++frame)
                {
                    Assert.That(translationsAfterBaking[transformIndex, frame], Is.EqualTo(translationsBeforeBaking[transformIndex, frame]).Using(positionComparer),
                                String.Format("Transform '{0}' position is set to {1} at frame {2}, but was expected to be {3}",
                                              targetTransforms[transformIndex].name, translationsAfterBaking[transformIndex, frame], frame, translationsBeforeBaking[transformIndex, frame]));
                }
            }
        }
    }