public static KeyframeAnimation Create(AnimationSampler animSampler, AnimationClip animationClip)
        {
            KeyframeAnimation anim = new KeyframeAnimation();

            anim.InitWithRigTransforms(animSampler.TargetRig);
            anim.duration  = Utility.ComputeAccurateClipDuration(animationClip);
            anim.numFrames = 0;

            var bindings = AnimationUtility.GetCurveBindings(animationClip);

            foreach (EditorCurveBinding binding in bindings)
            {
                int jointIndex = animSampler.TargetRig.GetJointIndexFromPath(binding.path);

                if (jointIndex >= 0)
                {
                    var curve = AnimationUtility.GetEditorCurve(animationClip, binding);

                    if (jointIndex == 0 && animationClip.hasMotionCurves)
                    {
                        if (binding.propertyName.Contains("Motion"))
                        {
                            anim.MapEditorCurve(jointIndex, binding.propertyName, "MotionT", "MotionQ", curve);
                        }
                    }
                    else if (jointIndex == 0 && animationClip.hasRootCurves)
                    {
                        if (binding.propertyName.Contains("Root"))
                        {
                            anim.MapEditorCurve(jointIndex, binding.propertyName, "RootT", "RootQ", curve);
                        }
                    }
                    else
                    {
                        anim.MapEditorCurve(jointIndex, binding.propertyName, "m_LocalPosition", "m_LocalRotation", curve);
                    }
                }
            }

            anim.animationCurves.Sort((x, y) => x.CompareTo(y));

            return(anim);
        }
        void ResetAnimationSampler()
        {
            DisableDisplayTrajectory();

            clip         = null;
            sourceAvatar = null;

            if (clipAssetCallbacks != null)
            {
                clipAssetCallbacks.Dispose();
                clipAssetCallbacks = null;
            }

            if (sampler != null)
            {
                sampler.Dispose();
                sampler = null;
            }

            previousTime = -1.0f;
        }
        bool InitAnimationSampler(TaggedAnimationClip clip)
        {
            this.clip = clip;

            if (clipAssetCallbacks != null)
            {
                clipAssetCallbacks.Dispose();
            }

            AnimationClip animationClip = clip.GetOrLoadClipSync();

            clipAssetCallbacks = new AssetPostprocessCallbacks(animationClip);
            clipAssetCallbacks.importDelegate = OnClipReimport;
            clipAssetCallbacks.deleteDelegate = OnClipDelete;

            sourceAvatar = clip.RetargetSourceAvatar;

            if (sampler != null)
            {
                sampler.Dispose();
                sampler = null;
            }

            try
            {
                sampler = new AnimationSampler(targetRig, animationClip);
            }
            catch (Exception e)
            {
                Debug.LogError(e.Message);
                return(false);
            }

            previousTime = -1.0f;

            return(true);
        }
        public IEnumerator BuildTransforms()
        {
            //
            // Now re-sample all animations according to the target
            // sample rate and adjust the segment information to
            // reference the transforms array.
            //

            //
            // Calculate total number of poses to be generated
            // (based on previously generated segments)
            //

            int numJoints = rig.NumJoints;

            if (numJoints < 2)
            {
                throw new ArgumentException($"Rig does not have enough joints. Only {numJoints} present.");
            }

            if (numFrames == 0)
            {
                throw new Exception("No animation frame to process, please make sure there is at least one single non-empty tag in your Kinematica asset.");
            }

            int numTransforms = numFrames * numJoints;

            using (NativeArray <AffineTransform> transforms = new NativeArray <AffineTransform>(numTransforms, Allocator.Persistent))
            {
                int globalSegmentIndex    = 0;
                int destinationFrameIndex = 0;
                for (int clipIndex = 0; clipIndex < clipSegments.Count; ++clipIndex)
                {
                    ClipSegments  segments = clipSegments[clipIndex];
                    AnimationClip clip     = segments.Clip.GetOrLoadClipSync();

                    using (AnimationSampler animSampler = new AnimationSampler(rig, clip))
                    {
                        float sourceSampleRate = clip.frameRate;
                        float targetSampleRate = asset.SampleRate;
                        float sampleRateRatio  = sourceSampleRate / targetSampleRate;

                        int numFrameResampledClip = (int)math.ceil(targetSampleRate * segments.Clip.DurationInSeconds);

                        for (int segmentIndex = 0; segmentIndex < segments.NumSegments; ++segmentIndex, ++globalSegmentIndex)
                        {
                            Segment segment = segments[segmentIndex];

                            int firstFrame = Missing.roundToInt(segment.source.FirstFrame / sampleRateRatio);
                            firstFrame = math.min(firstFrame, numFrameResampledClip - 1);

                            SampleRange sampleRange = new SampleRange()
                            {
                                startFrameIndex = firstFrame,
                                numFrames       = segment.destination.NumFrames
                            };

                            using (AnimationSampler.RangeSampler rangeSampler = animSampler.PrepareRangeSampler(asset.SampleRate, sampleRange, destinationFrameIndex, transforms))
                            {
                                rangeSampler.Schedule();

                                progressFeedback?.Invoke(new ProgressInfo()
                                {
                                    title    = $"Sample clip {clip.name}",
                                    progress = (float)globalSegmentIndex / numSegments
                                });

                                while (!rangeSampler.IsComplete)
                                {
                                    yield return(null);

                                    if (bCancel)
                                    {
                                        rangeSampler.Complete();
                                        yield break;
                                    }
                                }

                                rangeSampler.Complete();
                            }

                            destinationFrameIndex += segment.destination.NumFrames;
                        }
                    }
                }

                WriteTransformsToBinary(transforms);
            }
        }