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;
        }
        public IEnumerator Execute(List <FreeControllerV3> controllers)
        {
            var containingAtom = _containingAtom;
            var keyOps         = new KeyframesOperations(clip);
            var targetOps      = new TargetsOperations(_containingAtom, _animation, clip);

            yield return(0);

            var controlCounter = 0;
            var motControls    = containingAtom.motionAnimationControls
                                 .Where(m => m?.clip?.clipLength > 0.1f)
                                 .Where(m => controllers.Count == 0 || controllers.Contains(m.controller))
                                 .Where(m => m.clip.steps.Any(s => s.positionOn || s.rotationOn))
                                 .ToList();

            foreach (var mot in motControls)
            {
                FreeControllerAnimationTarget target = null;
                FreeControllerV3 ctrl;

                yield return(new Progress {
                    controllersProcessed = ++controlCounter, controllersTotal = motControls.Count
                });

                try
                {
                    ctrl   = mot.controller;
                    target = clip.targetControllers.FirstOrDefault(t => t.controller == ctrl);

                    if (_animation.index.ByLayer().Where(l => l.Key != clip.animationLayer).Select(l => l.Value.First()).SelectMany(c => c.targetControllers).Any(t2 => t2.controller == ctrl))
                    {
                        SuperController.LogError($"Skipping controller {ctrl.name} because it was used in another layer.");
                        continue;
                    }

                    if (target == null)
                    {
                        target = targetOps.Add(ctrl);
                        target.AddEdgeFramesIfMissing(clip.animationLength);
                    }
                    else
                    {
                        keyOps.RemoveAll(target);
                    }
                    target.StartBulkUpdates();
                    target.Validate(clip.animationLength);

                    var enumerator = ProcessController(mot.clip, target, ctrl).GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        yield return(enumerator.Current);
                    }
                }
                finally
                {
                    // NOTE: This should not be necessary, but for some reason dirty is set back to false too early and some changes are not picked up
                    target.dirty = true;
                    target?.EndBulkUpdates();
                }
            }
        }
        private void DeserializeClip(AtomAnimationClip clip, JSONClass clipJSON)
        {
            var animationPatternUID = clipJSON["AnimationPattern"]?.Value;

            if (!string.IsNullOrEmpty(animationPatternUID))
            {
                var animationPattern = SuperController.singleton.GetAtomByUid(animationPatternUID)?.GetComponentInChildren <AnimationPattern>();
                if (animationPattern == null)
                {
                    SuperController.LogError($"Animation Pattern '{animationPatternUID}' linked to animation '{clip.animationName}' of atom '{_atom.uid}' was not found in scene");
                }
                else
                {
                    clip.animationPattern = animationPattern;
                }
            }

            JSONArray controllersJSON = clipJSON["Controllers"].AsArray;

            if (controllersJSON != null)
            {
                foreach (JSONClass controllerJSON in controllersJSON)
                {
                    var controllerName = controllerJSON["Controller"].Value;
                    var controller     = _atom.freeControllers.Single(fc => fc.name == controllerName);
                    if (controller == null)
                    {
                        SuperController.LogError($"VamTimeline: Atom '{_atom.uid}' does not have a controller '{controllerName}'");
                        continue;
                    }
                    var target = new FreeControllerAnimationTarget(controller);
                    clip.Add(target);
                    DeserializeCurve(target.x, controllerJSON["X"], clip.animationLength, target.settings);
                    DeserializeCurve(target.y, controllerJSON["Y"], clip.animationLength);
                    DeserializeCurve(target.z, controllerJSON["Z"], clip.animationLength);
                    DeserializeCurve(target.rotX, controllerJSON["RotX"], clip.animationLength);
                    DeserializeCurve(target.rotY, controllerJSON["RotY"], clip.animationLength);
                    DeserializeCurve(target.rotZ, controllerJSON["RotZ"], clip.animationLength);
                    DeserializeCurve(target.rotW, controllerJSON["RotW"], clip.animationLength);
                    AddMissingKeyframeSettings(target);
                    target.AddEdgeFramesIfMissing(clip.animationLength);
                }
            }

            JSONArray floatParamsJSON = clipJSON["FloatParams"].AsArray;

            if (floatParamsJSON != null)
            {
                foreach (JSONClass paramJSON in floatParamsJSON)
                {
                    var storableId     = paramJSON["Storable"].Value;
                    var floatParamName = paramJSON["Name"].Value;
                    var target         = new FloatParamAnimationTarget(_atom, storableId, floatParamName);
                    clip.Add(target);
                    DeserializeCurve(target.value, paramJSON["Value"], clip.animationLength, target.settings);
                    AddMissingKeyframeSettings(target);
                    target.AddEdgeFramesIfMissing(clip.animationLength);
                }
            }

            JSONArray triggersJSON = clipJSON["Triggers"].AsArray;

            if (triggersJSON != null)
            {
                foreach (JSONClass triggerJSON in triggersJSON)
                {
                    var target = new TriggersAnimationTarget
                    {
                        name = DeserializeString(triggerJSON["Name"], "Trigger")
                    };
                    foreach (JSONClass entryJSON in triggerJSON["Triggers"].AsArray)
                    {
                        var trigger = new AtomAnimationTrigger();
                        trigger.RestoreFromJSON(entryJSON);
                        target.SetKeyframe(trigger.startTime, trigger);
                    }
                    target.AddEdgeFramesIfMissing(clip.animationLength);
                    clip.Add(target);
                }
            }
        }
示例#4
0
        public List <AtomAnimationClip> ImportClip(AtomAnimationClip clip)
        {
            var clips = new List <AtomAnimationClip>();

            var matchingLayer = _animation.clips.FirstOrDefault(c =>
            {
                // We only need to match float params and controllers, triggers can be in any layers
                if (!clip.targetFloatParams.All(t => c.targetFloatParams.Any(t.TargetsSameAs)))
                {
                    return(false);
                }
                if (!clip.targetControllers.All(t => c.targetControllers.Any(t.TargetsSameAs)))
                {
                    return(false);
                }
                return(true);
            });

            if (matchingLayer != null)
            {
                clip.animationLayer = matchingLayer.animationLayer;

                // Add missing targets
                foreach (var target in matchingLayer.targetFloatParams)
                {
                    if (!clip.targetFloatParams.Any(t => target.TargetsSameAs(t)))
                    {
                        var missing = new FloatParamAnimationTarget(target);
                        missing.AddEdgeFramesIfMissing(clip.animationLength);
                        clip.Add(missing);
                    }
                }
                foreach (var target in matchingLayer.targetControllers)
                {
                    if (!clip.targetControllers.Any(t => target.TargetsSameAs(t)))
                    {
                        var missing = new FreeControllerAnimationTarget(target.controller);
                        missing.AddEdgeFramesIfMissing(clip.animationLength);
                        clip.Add(missing);
                    }
                }
            }
            else if (_animation.index.ByLayer(clip.animationLayer).Any())
            {
                clip.animationLayer = new LayersOperations(_animation, clip).GetNewLayerName();
            }

            foreach (var controller in clip.targetControllers.Select(t => t.controller))
            {
                if (_animation.clips.Where(c => c.animationLayer != clip.animationLayer).Any(c => c.targetControllers.Any(t => t.controller == controller)))
                {
                    if (!_silent)
                    {
                        SuperController.LogError($"Timeline: Imported animation contains controller {controller.name} in layer {clip.animationLayer}, but that controller is already used elsewhere in your animation. To import, a layer is needed with targets: {string.Join(", ", clip.GetAllCurveTargets().Select(c => c.GetShortName()).ToArray())}");
                    }
                    return(clips);
                }
            }

            foreach (var floatParam in clip.targetFloatParams.Select(t => t.name))
            {
                if (_animation.clips.Where(c => c.animationLayer != clip.animationLayer).Any(c => c.targetFloatParams.Any(t => t.name == floatParam)))
                {
                    if (!_silent)
                    {
                        SuperController.LogError($"Timeline: Imported animation contains storable float {floatParam} in layer {clip.animationLayer}, but that storable is already used elsewhere in your animation. To import, a layer is needed with targets: {string.Join(", ", clip.GetAllCurveTargets().Select(c => c.GetShortName()).ToArray())}");
                    }
                    return(clips);
                }
            }

            var existingClip = _animation.GetClip(clip.animationLayer, clip.animationName);

            if (existingClip != null)
            {
                if (existingClip.IsEmpty())
                {
                    _animation.clips.Remove(existingClip);
                    existingClip.Dispose();
                }
                else
                {
                    var newAnimationName = GenerateUniqueAnimationName(clip.animationLayer, clip.animationName);
                    if (!_silent)
                    {
                        SuperController.LogError($"Timeline: Imported clip '{clip.animationNameQualified}' already exists and will be imported with the name {newAnimationName}");
                    }
                    clip.animationName = newAnimationName;
                }
            }

            clips.Add(clip);
            return(clips);
        }
示例#5
0
        private IEnumerator ImportRecordedCoroutine()
        {
            var containingAtom = plugin.containingAtom;
            var totalStopwatch = Stopwatch.StartNew();

            yield return(0);

            var controlCounter = 0;
            var filterSelected = current.targetControllers.Any(c => c.selected);

            foreach (var mot in containingAtom.motionAnimationControls)
            {
                FreeControllerAnimationTarget target = null;
                FreeControllerV3 ctrl;

                _importRecordedUI.buttonText.text = $"Importing, please wait... ({++controlCounter} / {containingAtom.motionAnimationControls.Length})";

                try
                {
                    if (mot == null || mot.clip == null)
                    {
                        continue;
                    }
                    if (mot.clip.clipLength <= 0.1)
                    {
                        continue;
                    }
                    ctrl   = mot.controller;
                    target = current.targetControllers.FirstOrDefault(t => t.controller == ctrl);
                    if (filterSelected && (target == null || !target.selected))
                    {
                        continue;
                    }

                    if (animation.EnumerateLayers().Where(l => l != current.animationLayer).Select(l => animation.clips.First(c => c.animationLayer == l)).SelectMany(c => c.targetControllers).Any(t2 => t2.controller == ctrl))
                    {
                        SuperController.LogError($"Skipping controller {ctrl.name} because it was used in another layer.");
                        continue;
                    }

                    if (target == null)
                    {
                        if (!mot.clip.steps.Any(s => s.positionOn || s.rotationOn))
                        {
                            continue;
                        }
                        target = operations.Targets().Add(ctrl);
                        target.AddEdgeFramesIfMissing(current.animationLength);
                    }
                    target.Validate(current.animationLength);
                    target.StartBulkUpdates();
                    operations.Keyframes().RemoveAll(target);
                }
                catch (Exception exc)
                {
                    SuperController.LogError($"VamTimeline.{nameof(MocapScreen)}.{nameof(ImportRecordedCoroutine)}[Init]: {exc}");
                    target?.EndBulkUpdates();
                    yield break;
                }

                IEnumerator enumerator;
                try
                {
                    if (_importRecordedOptionsJSON.val == "Keyframe Reduction")
                    {
                        enumerator = ExtractFramesWithReductionTechnique(mot.clip, target, ctrl).GetEnumerator();
                    }
                    else
                    {
                        enumerator = ExtractFramesWithFpsTechnique(mot.clip, target, ctrl).GetEnumerator();
                    }
                }
                catch
                {
                    target.EndBulkUpdates();
                    throw;
                }

                while (TryMoveNext(enumerator, target))
                {
                    yield return(enumerator.Current);
                }

                target.EndBulkUpdates();
            }

            _importRecordedUI.buttonText.text     = "Import recorded animation (mocap)";
            _importRecordedUI.button.interactable = true;
        }