public static List <ClipSegments> GenerateSegments(Asset asset, out int numSegments, out int numFrames)
            {
                List <ClipSegments> segments = new List <ClipSegments>();

                int destinationIndex = 0;

                numSegments = 0;
                numFrames   = 0;

                foreach (var animationClip in asset.GetAnimationClips())
                {
                    ClipSegments clipSegments = new ClipSegments()
                    {
                        clip     = animationClip,
                        segments = GenerateSegments(asset, animationClip)
                    };

                    numSegments += clipSegments.NumSegments;

                    foreach (var segment in clipSegments.segments)
                    {
                        Assert.IsTrue(segment.source.FirstFrame >= 0);
                        Assert.IsTrue(segment.source.OnePastLastFrame <= animationClip.NumFrames);

                        int numFramesSource      = segment.source.NumFrames;
                        int numFramesDestination = animationClip.ClipFramesToAssetFrames(asset, numFramesSource);

                        int onePastLastFrame = destinationIndex + numFramesDestination;

                        numFrames += numFramesDestination;

                        segment.destination =
                            new Interval(destinationIndex, onePastLastFrame);

                        destinationIndex += numFramesDestination;
                    }

                    segments.Add(clipSegments);
                }

                return(segments);
            }
        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);
            }
        }