public ICurveAnimationTarget Clone(bool copyKeyframes)
        {
            var clone = new FreeControllerAnimationTarget(controller);

            if (copyKeyframes)
            {
                clone.x.keys.AddRange(x.keys);
                clone.y.keys.AddRange(y.keys);
                clone.z.keys.AddRange(z.keys);
                clone.rotX.keys.AddRange(rotX.keys);
                clone.rotY.keys.AddRange(rotY.keys);
                clone.rotZ.keys.AddRange(rotZ.keys);
                clone.rotW.keys.AddRange(rotW.keys);
            }
            else
            {
                clone.SetKeyframe(0f, GetKeyframePosition(0), GetKeyframeRotation(0), CurveTypeValues.SmoothLocal);
                clone.SetKeyframe(GetKeyframeTime(x.length - 1), GetKeyframePosition(x.length - 1), GetKeyframeRotation(x.length - 1), CurveTypeValues.SmoothLocal);
                clone.ComputeCurves();
            }
            return(clone);
        }
Пример #2
0
        private IEnumerable ExtractFramesWithFpsTechnique(MotionAnimationClip clip, FreeControllerAnimationTarget target, FreeControllerV3 ctrl)
        {
            var minPositionDistanceForFlat = 0.01f;
            var batchStopwatch             = Stopwatch.StartNew();
            var containingAtom             = plugin.containingAtom;
            var frameLength = 1f / _reduceMaxFramesPerSecondJSON.val;

            var lastRecordedFrame            = float.MinValue;
            MotionAnimationStep previousStep = null;

            for (var stepIndex = 0; stepIndex < (clip.steps.Count - (current.loop ? 1 : 0)); stepIndex++)
            {
                try
                {
                    var step = clip.steps[stepIndex];
                    var time = step.timeStep.Snap(0.01f);
                    if (time - lastRecordedFrame < frameLength)
                    {
                        continue;
                    }
                    var k = ControllerKeyframe.FromStep(time, step, containingAtom, ctrl);
                    target.SetKeyframe(time, k.position, k.rotation);
                    if (previousStep != null && (target.controller.name == "lFootControl" || target.controller.name == "rFootControl") && Vector3.Distance(previousStep.position, step.position) <= minPositionDistanceForFlat)
                    {
                        KeyframeSettings settings;
                        if (target.settings.TryGetValue(previousStep.timeStep.Snap().ToMilliseconds(), out settings))
                        {
                            target.ChangeCurve(previousStep.timeStep, CurveTypeValues.Linear);
                        }
                    }
                    lastRecordedFrame = time;
                    previousStep      = step;
                }
                catch (Exception exc)
                {
                    SuperController.LogError($"VamTimeline.{nameof(MocapScreen)}.{nameof(ImportRecordedCoroutine)}[Step]: {exc}");
                    yield break;
                }

                if (batchStopwatch.ElapsedMilliseconds > 5)
                {
                    batchStopwatch.Reset();
                    yield return(0);

                    batchStopwatch.Start();
                }
            }
        }
Пример #3
0
        protected IEnumerable ProcessController(MotionAnimationClip motClip, FreeControllerAnimationTarget target, FreeControllerV3 ctrl)
        {
            var frameLength = 0.001f;

            var lastRecordedFrame = float.MinValue;

            // Vector3? previousPosition = null;
            // var previousTime = 0f;
            for (var stepIndex = 0; stepIndex < motClip.steps.Count - (clip.loop ? 1 : 0); stepIndex++)
            {
                var step = motClip.steps[stepIndex];
                var time = step.timeStep.Snap(0.01f);
                if (time - lastRecordedFrame < frameLength)
                {
                    continue;
                }
                if (time > clip.animationLength)
                {
                    break;
                }
                if (Mathf.Abs(time - clip.animationLength) < 0.001f)
                {
                    time = clip.animationLength;
                }
                var k = ControllerKeyframe.FromStep(time, step, ctrl);
                target.SetKeyframe(time, k.position, k.rotation, CurveTypeValues.SmoothLocal);
                // SuperController.LogMessage($"{k.position.x:0.0000}, {k.position.y:0.0000},{k.position.z:0.0000}");
                // if (previousPosition.HasValue && (target.controller.name == "lFootControl" || target.controller.name == "rFootControl") && Vector3.Distance(previousPosition.Value, step.position) <= minPositionDistanceForFlat)
                // {
                //     target.ChangeCurve(previousTime, CurveTypeValues.Linear);
                // }
                lastRecordedFrame = time;
                // previousPosition = step.position;
                // previousTime = time;
            }

            target.AddEdgeFramesIfMissing(clip.animationLength);
            yield break;
        }
Пример #4
0
        private IEnumerable ExtractFramesWithReductionTechnique(MotionAnimationClip clip, FreeControllerAnimationTarget target, FreeControllerV3 ctrl)
        {
            var minFrameDistance = 1f / _reduceMaxFramesPerSecondJSON.val;
            var maxIterations    = (int)(clip.clipLength * 10);

            var containingAtom = plugin.containingAtom;
            var steps          = clip.steps
                                 .Where(s => s.positionOn || s.rotationOn)
                                 .GroupBy(s => s.timeStep.Snap(minFrameDistance).ToMilliseconds())
                                 .Select(g =>
            {
                var step = g.OrderBy(s => Math.Abs(g.Key - s.timeStep)).First();
                return(ControllerKeyframe.FromStep((g.Key / 1000f).Snap(), step, containingAtom, ctrl));
            })
                                 .ToList();

            if (steps.Count < 2)
            {
                yield break;
            }

            target.SetKeyframe(0, steps[0].position, steps[0].rotation);
            target.SetKeyframe(current.animationLength, steps[steps.Count - 1].position, steps[steps.Count - 1].rotation);

            var buckets = new List <ReducerBucket>
            {
                Scan(steps, target, 1, steps.Count - 2)
            };

            for (var iteration = 0; iteration < maxIterations; iteration++)
            {
                // Scan for largest difference with curve
                var bucketWithLargestPositionDistance = -1;
                var keyWithLargestPositionDistance    = -1;
                var largestPositionDistance           = 0f;
                var bucketWithLargestRotationAngle    = -1;
                var keyWithLargestRotationAngle       = -1;
                var largestRotationAngle = 0f;
                for (var bucketIndex = 0; bucketIndex < buckets.Count; bucketIndex++)
                {
                    var bucket = buckets[bucketIndex];
                    if (bucket.largestPositionDistance > largestPositionDistance)
                    {
                        largestPositionDistance           = bucket.largestPositionDistance;
                        keyWithLargestPositionDistance    = bucket.keyWithLargestPositionDistance;
                        bucketWithLargestPositionDistance = bucketIndex;
                    }
                    if (bucket.largestRotationAngle > largestRotationAngle)
                    {
                        largestRotationAngle           = bucket.largestRotationAngle;
                        keyWithLargestRotationAngle    = bucket.keyWithLargestRotationAngle;
                        bucketWithLargestRotationAngle = bucketIndex;
                    }
                }

                // Cannot find large enough diffs, exit
                if (keyWithLargestRotationAngle == -1 || keyWithLargestPositionDistance == -1)
                {
                    break;
                }
                var posInRange = largestPositionDistance >= _reduceMinPosDistanceJSON.val;
                var rotInRange = largestRotationAngle >= _reduceMinRotationJSON.val;
                if (!posInRange && !rotInRange)
                {
                    break;
                }

                // This is an attempt to compare translations and rotations
                var normalizedPositionDistance = largestPositionDistance / 0.4f;
                var normalizedRotationAngle    = largestRotationAngle / 180f;
                var selectPosOverRot           = (normalizedPositionDistance > normalizedRotationAngle) && posInRange;
                var keyToApply = selectPosOverRot ? keyWithLargestPositionDistance : keyWithLargestRotationAngle;

                var step = steps[keyToApply];
                var key  = target.SetKeyframe(step.time, step.position, step.rotation);
                target.SmoothNeighbors(key);

                int bucketToSplitIndex;
                if (selectPosOverRot)
                {
                    bucketToSplitIndex = bucketWithLargestPositionDistance;
                }
                else
                {
                    bucketToSplitIndex = bucketWithLargestRotationAngle;
                }

                if (bucketToSplitIndex > -1)
                {
                    // Split buckets and exclude the scanned keyframe, we never have to scan it again.
                    var bucketToSplit = buckets[bucketToSplitIndex];
                    buckets.RemoveAt(bucketToSplitIndex);
                    if (bucketToSplit.to - keyToApply + 1 > 2)
                    {
                        buckets.Insert(bucketToSplitIndex, Scan(steps, target, keyToApply + 1, bucketToSplit.to));
                    }
                    if (keyToApply - 1 - bucketToSplit.from > 2)
                    {
                        buckets.Insert(bucketToSplitIndex, Scan(steps, target, bucketToSplit.from, keyToApply - 1));
                    }
                }

                yield return(0);
            }
        }