Пример #1
0
        private bool GetPatchAtPath(TargetPath path, out IPatchable patch)
        {
            var targetId = TargetMap[path.Placeholder];

            if (path.AnimatibleType == "actor")
            {
                // pull current value
                var        actor      = (Actor)manager.App.FindActor(targetId);
                ActorPatch actorPatch = (ActorPatch)manager.AnimInputPatches.GetOrCreate(targetId, () => new ActorPatch(targetId));
                if (actor?.GeneratePatch(actorPatch, path) != null)
                {
                    patch = actorPatch;
                    return(true);
                }
            }

            patch = null;
            return(false);
        }
        internal void Interpolate(
            ActorPatch finalFrame,
            string animationName,
            float duration,
            float[] curve,
            bool enabled)
        {
            // Ensure duration is in range [0...n].
            duration = Math.Max(0, duration);

            const int FPS      = 10;
            float     timeStep = duration / FPS;

            // If the curve is malformed, fall back to linear.
            if (curve.Length != 4)
            {
                curve = new float[] { 0, 0, 1, 1 };
            }

            // Are we patching the transform?
            bool animateTransform = finalFrame.Transform != null && finalFrame.Transform.Local != null && finalFrame.Transform.Local.IsPatched();
            var  finalTransform   = finalFrame.Transform.Local;

            // What parts of the transform are we animating?
            bool animatePosition = animateTransform && finalTransform.Position != null && finalTransform.Position.IsPatched();
            bool animateRotation = animateTransform && finalTransform.Rotation != null && finalTransform.Rotation.IsPatched();
            bool animateScale    = animateTransform && finalTransform.Scale != null && finalTransform.Scale.IsPatched();

            // Ensure we have a well-formed rotation quaternion.
            for (; animateRotation;)
            {
                var  rotation         = finalTransform.Rotation;
                bool hasAllComponents =
                    rotation.X.HasValue &&
                    rotation.Y.HasValue &&
                    rotation.Z.HasValue &&
                    rotation.W.HasValue;

                // If quaternion is incomplete, fall back to the identity.
                if (!hasAllComponents)
                {
                    finalTransform.Rotation = new QuaternionPatch(Quaternion.identity);
                    break;
                }

                // Ensure the quaternion is normalized.
                var lengthSquared =
                    (rotation.X.Value * rotation.X.Value) +
                    (rotation.Y.Value * rotation.Y.Value) +
                    (rotation.Z.Value * rotation.Z.Value) +
                    (rotation.W.Value * rotation.W.Value);
                if (lengthSquared == 0)
                {
                    // If the quaternion is length zero, fall back to the identity.
                    finalTransform.Rotation = new QuaternionPatch(Quaternion.identity);
                    break;
                }
                else if (lengthSquared != 1.0f)
                {
                    // If the quaternion length is not 1, normalize it.
                    var inverseLength = 1.0f / Mathf.Sqrt(lengthSquared);
                    rotation.X *= inverseLength;
                    rotation.Y *= inverseLength;
                    rotation.Z *= inverseLength;
                    rotation.W *= inverseLength;
                }
                break;
            }

            // Create the sampler to calculate ease curve values.
            var sampler = new CubicBezier(curve[0], curve[1], curve[2], curve[3]);

            var keyframes = new List <MWAnimationKeyframe>();

            // Generate keyframes
            float currTime = 0;

            do
            {
                var keyframe = NewKeyframe(currTime);
                var unitTime = duration > 0 ? currTime / duration : 1;
                BuildKeyframe(keyframe, unitTime);
                keyframes.Add(keyframe);
                currTime += timeStep;
            }while (currTime <= duration && timeStep > 0);

            // Final frame (if needed)
            if (currTime - duration > 0)
            {
                var keyframe = NewKeyframe(duration);
                BuildKeyframe(keyframe, 1);
                keyframes.Add(keyframe);
            }

            // Create and optionally start the animation.
            CreateAnimation(
                animationName,
                keyframes,
                events: null,
                wrapMode: MWAnimationWrapMode.Once,
                initialState: new MWSetAnimationStateOptions {
                Enabled = enabled
            },
                isInternal: true,
                managed: false,
                onCreatedCallback: null);

            bool LerpFloat(out float dest, float start, float?end, float t)
            {
                if (end.HasValue)
                {
                    dest = Mathf.LerpUnclamped(start, end.Value, t);
                    return(true);
                }
                dest = 0;
                return(false);
            }

            bool SlerpQuaternion(out Quaternion dest, Quaternion start, QuaternionPatch end, float t)
            {
                if (end != null)
                {
                    dest = Quaternion.SlerpUnclamped(start, new Quaternion(end.X.Value, end.Y.Value, end.Z.Value, end.W.Value), t);
                    return(true);
                }
                dest = Quaternion.identity;
                return(false);
            }

            void BuildKeyframePosition(MWAnimationKeyframe keyframe, float t)
            {
                float value;

                if (LerpFloat(out value, transform.localPosition.x, finalTransform.Position.X, t))
                {
                    keyframe.Value.Transform.Local.Position.X = value;
                }
                if (LerpFloat(out value, transform.localPosition.y, finalTransform.Position.Y, t))
                {
                    keyframe.Value.Transform.Local.Position.Y = value;
                }
                if (LerpFloat(out value, transform.localPosition.z, finalTransform.Position.Z, t))
                {
                    keyframe.Value.Transform.Local.Position.Z = value;
                }
            }

            void BuildKeyframeScale(MWAnimationKeyframe keyframe, float t)
            {
                float value;

                if (LerpFloat(out value, transform.localScale.x, finalTransform.Scale.X, t))
                {
                    keyframe.Value.Transform.Local.Scale.X = value;
                }
                if (LerpFloat(out value, transform.localScale.y, finalTransform.Scale.Y, t))
                {
                    keyframe.Value.Transform.Local.Scale.Y = value;
                }
                if (LerpFloat(out value, transform.localScale.z, finalTransform.Scale.Z, t))
                {
                    keyframe.Value.Transform.Local.Scale.Z = value;
                }
            }

            void BuildKeyframeRotation(MWAnimationKeyframe keyframe, float t)
            {
                Quaternion value;

                if (SlerpQuaternion(out value, transform.localRotation, finalTransform.Rotation, t))
                {
                    keyframe.Value.Transform.Local.Rotation = new QuaternionPatch(value);
                }
            }

            void BuildKeyframe(MWAnimationKeyframe keyframe, float unitTime)
            {
                float curveTime = sampler.Sample(unitTime);

                if (animatePosition)
                {
                    BuildKeyframePosition(keyframe, curveTime);
                }
                if (animateRotation)
                {
                    BuildKeyframeRotation(keyframe, curveTime);
                }
                if (animateScale)
                {
                    BuildKeyframeScale(keyframe, curveTime);
                }
            }

            MWAnimationKeyframe NewKeyframe(float time)
            {
                var keyframe = new MWAnimationKeyframe
                {
                    Time  = time,
                    Value = new ActorPatch()
                };

                if (animateTransform)
                {
                    keyframe.Value.Transform = new ActorTransformPatch()
                    {
                        Local = new ScaledTransformPatch()
                    };
                }
                if (animatePosition)
                {
                    keyframe.Value.Transform.Local.Position = new Vector3Patch();
                }
                if (animateRotation)
                {
                    keyframe.Value.Transform.Local.Rotation = new QuaternionPatch();
                }
                if (animateScale)
                {
                    keyframe.Value.Transform.Local.Scale = new Vector3Patch();
                }
                return(keyframe);
            }
        }
 internal ActorChangedEvent(Guid actorId, ActorPatch actor)
     : base(actorId)
 {
     _actor = actor;
 }