Beispiel #1
0
        private static bool ShouldApplyOffset(AppliedOffsetMode mode, AnimationClip clip)
        {
            if (mode == AppliedOffsetMode.NoRootTransform || mode == AppliedOffsetMode.SceneOffsetLegacy)
            {
                return(false);
            }

            return(HasRootTransforms(clip));
        }
Beispiel #2
0
        static bool UsesAbsoluteMotion(AppliedOffsetMode mode)
        {
#if UNITY_EDITOR
            // in editor, previewing is always done in absolute motion
            if (!Application.isPlaying)
            {
                return(true);
            }
#endif
            return(mode != AppliedOffsetMode.SceneOffset &&
                   mode != AppliedOffsetMode.SceneOffsetLegacy);
        }
Beispiel #3
0
 bool RequiresMotionXPlayable(AppliedOffsetMode mode, GameObject gameObject)
 {
     if (mode == AppliedOffsetMode.NoRootTransform)
     {
         return(false);
     }
     if (mode == AppliedOffsetMode.SceneOffsetLegacy)
     {
         var animator = GetBinding(gameObject != null ? gameObject.GetComponent <PlayableDirector>() : null);
         return(animator != null && animator.hasRootMotion);
     }
     return(true);
 }
Beispiel #4
0
        Playable ApplyTrackOffset(PlayableGraph graph, Playable root, GameObject go, AppliedOffsetMode mode)
        {
#if UNITY_EDITOR
            m_ClipOffset = AnimationOffsetPlayable.Null;
#endif

            // offsets don't apply in scene offset, or if there is no root transform (globally or on this track)
            if (mode == AppliedOffsetMode.SceneOffsetLegacy ||
                mode == AppliedOffsetMode.SceneOffset ||
                mode == AppliedOffsetMode.NoRootTransform ||
                !AnimatesRootTransform()
                )
            {
                return(root);
            }


            var pos = position;
            var rot = rotation;

#if UNITY_EDITOR
            // in the editor use the preview position to playback from if available
            if (mode == AppliedOffsetMode.SceneOffsetEditor)
            {
                pos = m_SceneOffsetPosition;
                rot = Quaternion.Euler(m_SceneOffsetRotation);
            }
#endif

            var offsetPlayable = AnimationOffsetPlayable.Create(graph, pos, rot, 1);
#if UNITY_EDITOR
            m_ClipOffset = offsetPlayable;
#endif
            graph.Connect(root, 0, offsetPlayable, 0);
            offsetPlayable.SetInputWeight(0, 1);

            return(offsetPlayable);
        }
Beispiel #5
0
        Playable CreateInfiniteTrackPlayable(PlayableGraph graph, GameObject go, IntervalTree <RuntimeElement> tree, AppliedOffsetMode mode)
        {
            if (m_InfiniteClip == null)
            {
                return(Playable.Null);
            }

            var mixer = AnimationMixerPlayable.Create(graph, 1);

            // In infinite mode, we always force the loop mode of the clip off because the clip keys are offset in infinite mode
            //  which causes loop to behave different.
            // The inline curve editor never shows loops in infinite mode.
            var playable = AnimationPlayableAsset.CreatePlayable(graph, m_InfiniteClip, m_InfiniteClipOffsetPosition, m_InfiniteClipOffsetEulerAngles, false, mode, infiniteClipApplyFootIK, AnimationPlayableAsset.LoopMode.Off);

            if (playable.IsValid())
            {
                tree.Add(new InfiniteRuntimeClip(playable));
                graph.Connect(playable, 0, mixer, 0);
                mixer.SetInputWeight(0, 1.0f);
            }

            return(ApplyTrackOffset(graph, mixer, go, mode));
        }
Beispiel #6
0
        internal override Playable OnCreateClipPlayableGraph(PlayableGraph graph, GameObject go, IntervalTree <RuntimeElement> tree)
        {
            if (isSubTrack)
            {
                throw new InvalidOperationException("Nested animation tracks should never be asked to create a graph directly");
            }

            List <AnimationTrack> flattenTracks = new List <AnimationTrack>();

            if (CanCompileClips())
            {
                flattenTracks.Add(this);
            }

            var genericRoot = GetGenericRootNode(go);
            var animatesRootTransformNoMask = AnimatesRootTransform();
            var animatesRootTransform       = animatesRootTransformNoMask && !IsRootTransformDisabledByMask(go, genericRoot);

            foreach (var subTrack in GetChildTracks())
            {
                var child = subTrack as AnimationTrack;
                if (child != null && child.CanCompileClips())
                {
                    var childAnimatesRoot = child.AnimatesRootTransform();
                    animatesRootTransformNoMask |= child.AnimatesRootTransform();
                    animatesRootTransform       |= (childAnimatesRoot && !child.IsRootTransformDisabledByMask(go, genericRoot));
                    flattenTracks.Add(child);
                }
            }

            // figure out which mode to apply
            AppliedOffsetMode mode = GetOffsetMode(go, animatesRootTransform);
            int defaultBlendCount  = GetDefaultBlendCount();
            var layerMixer         = CreateGroupMixer(graph, go, flattenTracks.Count + defaultBlendCount);

            for (int c = 0; c < flattenTracks.Count; c++)
            {
                int blendIndex = c + defaultBlendCount;
                // if the child is masking the root transform, compile it as if we are non-root mode
                var childMode = mode;
                if (mode != AppliedOffsetMode.NoRootTransform && flattenTracks[c].IsRootTransformDisabledByMask(go, genericRoot))
                {
                    childMode = AppliedOffsetMode.NoRootTransform;
                }

                var compiledTrackPlayable = flattenTracks[c].inClipMode ?
                                            CompileTrackPlayable(graph, flattenTracks[c], go, tree, childMode) :
                                            flattenTracks[c].CreateInfiniteTrackPlayable(graph, go, tree, childMode);
                graph.Connect(compiledTrackPlayable, 0, layerMixer, blendIndex);
                layerMixer.SetInputWeight(blendIndex, flattenTracks[c].inClipMode ? 0 : 1);
                if (flattenTracks[c].applyAvatarMask && flattenTracks[c].avatarMask != null)
                {
                    layerMixer.SetLayerMaskFromAvatarMask((uint)blendIndex, flattenTracks[c].avatarMask);
                }
            }

            var requiresMotionXPlayable = RequiresMotionXPlayable(mode, go);

            // In the editor, we may require the motion X playable if we are animating the root transform but it is masked out, because the default poses
            //  need to properly update root motion
            requiresMotionXPlayable |= (defaultBlendCount > 0 && RequiresMotionXPlayable(GetOffsetMode(go, animatesRootTransformNoMask), go));

            // Attach the default poses
            AttachDefaultBlend(graph, layerMixer, requiresMotionXPlayable);

            // motionX playable not required in scene offset mode, or root transform mode
            Playable mixer = layerMixer;

            if (requiresMotionXPlayable)
            {
                // If we are animating a root transform, add the motionX to delta playable as the root node
                var motionXToDelta = AnimationMotionXToDeltaPlayable.Create(graph);
                graph.Connect(mixer, 0, motionXToDelta, 0);
                motionXToDelta.SetInputWeight(0, 1.0f);
                motionXToDelta.SetAbsoluteMotion(UsesAbsoluteMotion(mode));
                mixer = (Playable)motionXToDelta;
            }


#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                var animator = GetBinding(go != null ? go.GetComponent <PlayableDirector>() : null);
                if (animator != null)
                {
                    GameObject targetGO = animator.gameObject;
                    IAnimationWindowPreview[] previewComponents = targetGO.GetComponents <IAnimationWindowPreview>();

                    m_HasPreviewComponents = previewComponents.Length > 0;
                    if (m_HasPreviewComponents)
                    {
                        foreach (var component in previewComponents)
                        {
                            mixer = component.BuildPreviewGraph(graph, mixer);
                        }
                    }
                }
            }
#endif

            return(mixer);
        }
Beispiel #7
0
        Playable CompileTrackPlayable(PlayableGraph graph, TrackAsset track, GameObject go, IntervalTree <RuntimeElement> tree, AppliedOffsetMode mode)
        {
            var mixer = AnimationMixerPlayable.Create(graph, track.clips.Length);

            for (int i = 0; i < track.clips.Length; i++)
            {
                var c     = track.clips[i];
                var asset = c.asset as PlayableAsset;
                if (asset == null)
                {
                    continue;
                }

                var animationAsset = asset as AnimationPlayableAsset;
                if (animationAsset != null)
                {
                    animationAsset.appliedOffsetMode = mode;
                }

                var source = asset.CreatePlayable(graph, go);
                if (source.IsValid())
                {
                    var clip = new RuntimeClip(c, source, mixer);
                    tree.Add(clip);
                    graph.Connect(source, 0, mixer, i);
                    mixer.SetInputWeight(i, 0.0f);
                }
            }

            return(ApplyTrackOffset(graph, mixer, go, mode));
        }
Beispiel #8
0
        internal override Playable OnCreateClipPlayableGraph(PlayableGraph graph, GameObject go, IntervalTree <RuntimeElement> tree)
        {
            if (isSubTrack)
            {
                throw new InvalidOperationException("Nested animation tracks should never be asked to create a graph directly");
            }

            List <AnimationTrack> flattenTracks = new List <AnimationTrack>();

            if (CanCompileClips())
            {
                flattenTracks.Add(this);
            }


            bool animatesRootTransform = AnimatesRootTransform();

            foreach (var subTrack in GetChildTracks())
            {
                var child = subTrack as AnimationTrack;
                if (child != null && child.CanCompileClips())
                {
                    animatesRootTransform |= child.AnimatesRootTransform();
                    flattenTracks.Add(child);
                }
            }

            // figure out which mode to apply
            AppliedOffsetMode mode = GetOffsetMode(go, animatesRootTransform);
            var layerMixer         = CreateGroupMixer(graph, go, flattenTracks.Count);

            for (int c = 0; c < flattenTracks.Count; c++)
            {
                var compiledTrackPlayable = flattenTracks[c].inClipMode ?
                                            CompileTrackPlayable(graph, flattenTracks[c], go, tree, mode) :
                                            flattenTracks[c].CreateInfiniteTrackPlayable(graph, go, tree, mode);
                graph.Connect(compiledTrackPlayable, 0, layerMixer, c);
                layerMixer.SetInputWeight(c, flattenTracks[c].inClipMode ? 0 : 1);
                if (flattenTracks[c].applyAvatarMask && flattenTracks[c].avatarMask != null)
                {
                    layerMixer.SetLayerMaskFromAvatarMask((uint)c, flattenTracks[c].avatarMask);
                }
            }

            bool requiresMotionXPlayable = RequiresMotionXPlayable(mode, go);

            Playable mixer = layerMixer;

            mixer = CreateDefaultBlend(graph, go, mixer, requiresMotionXPlayable);

            // motionX playable not required in scene offset mode, or root transform mode
            if (requiresMotionXPlayable)
            {
                // If we are animating a root transform, add the motionX to delta playable as the root node
                var motionXToDelta = AnimationMotionXToDeltaPlayable.Create(graph);
                graph.Connect(mixer, 0, motionXToDelta, 0);
                motionXToDelta.SetInputWeight(0, 1.0f);
                motionXToDelta.SetAbsoluteMotion(UsesAbsoluteMotion(mode));
                mixer = (Playable)motionXToDelta;
            }



#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                var animator = GetBinding(go != null ? go.GetComponent <PlayableDirector>() : null);
                if (animator != null)
                {
                    GameObject targetGO = animator.gameObject;
                    IAnimationWindowPreview[] previewComponents = targetGO.GetComponents <IAnimationWindowPreview>();

                    m_HasPreviewComponents = previewComponents.Length > 0;
                    if (m_HasPreviewComponents)
                    {
                        foreach (var component in previewComponents)
                        {
                            mixer = component.BuildPreviewGraph(graph, mixer);
                        }
                    }
                }
            }
#endif

            return(mixer);
        }
Beispiel #9
0
        internal override Playable OnCreateClipPlayableGraph(PlayableGraph graph, GameObject go, IntervalTree <RuntimeElement> tree)
        {
            if (isSubTrack)
            {
                throw new InvalidOperationException("Nested animation tracks should never be asked to create a graph directly");
            }

            List <AnimationTrack> flattenTracks = new List <AnimationTrack>();

            if (CanCompileClips())
            {
                flattenTracks.Add(this);
            }


            bool animatesRootTransform = AnimatesRootTransform();

            foreach (var subTrack in GetChildTracks())
            {
                var child = subTrack as AnimationTrack;
                if (child != null && child.CanCompileClips())
                {
                    animatesRootTransform |= child.AnimatesRootTransform();
                    flattenTracks.Add(child);
                }
            }

            // figure out which mode to apply
            AppliedOffsetMode mode = GetOffsetMode(go, animatesRootTransform);
            var layerMixer         = CreateGroupMixer(graph, go, flattenTracks.Count);

            for (int c = 0; c < flattenTracks.Count; c++)
            {
                var compiledTrackPlayable = flattenTracks[c].inClipMode ?
                                            CompileTrackPlayable(graph, flattenTracks[c], go, tree, mode) :
                                            flattenTracks[c].CreateInfiniteTrackPlayable(graph, go, tree, mode);
                graph.Connect(compiledTrackPlayable, 0, layerMixer, c);
                layerMixer.SetInputWeight(c, flattenTracks[c].inClipMode ? 0 : 1);
                if (flattenTracks[c].applyAvatarMask && flattenTracks[c].avatarMask != null)
                {
                    layerMixer.SetLayerMaskFromAvatarMask((uint)c, flattenTracks[c].avatarMask);
                }
            }

            Playable mixer = (Playable)layerMixer;

#if UNITY_EDITOR
            if (!Application.isPlaying)
            {
                var motionXMixer = AnimationMixerPlayable.Create(graph, 2);

                var      animator     = GetBinding(go != null ? go.GetComponent <PlayableDirector>() : null);
                Playable blendDefault = Playable.Null;
                if (animator != null && animator.isHuman)
                {
                    blendDefault = AnimationClipPlayable.Create(graph, GetDefaultHumanoidClip());
                }
                else
                {
                    blendDefault = AnimationPosePlayable.Create(graph);
                    ((AnimationPosePlayable)blendDefault).SetReadDefaultPose(true);
                }

                var offsetPlayable = AnimationOffsetPlayable.Create(graph, m_SceneOffsetPosition, Quaternion.Euler(m_SceneOffsetRotation), 1);

                graph.Connect(blendDefault, 0, offsetPlayable, 0);
                graph.Connect(layerMixer, 0, motionXMixer, 0);
                graph.Connect(offsetPlayable, 0, motionXMixer, 1);

                offsetPlayable.SetInputWeight(0, 1.0f);
                motionXMixer.SetInputWeight(1, 1.0f);
                motionXMixer.SetInputWeight(0, 0.0f);

                mixer = (Playable)motionXMixer;
            }
#endif

            // motionX playable not required in scene offset mode, or root transform mode
            if (!RequiresMotionXPlayable(mode, go))
            {
                return(mixer);
            }

            // If we are animating a root transform, add the motionX to delta playable as the root node
            var motionXToDelta = AnimationMotionXToDeltaPlayable.Create(graph);
            graph.Connect(mixer, 0, motionXToDelta, 0);
            motionXToDelta.SetInputWeight(0, 1.0f);
            motionXToDelta.SetAbsoluteMotion(UsesAbsoluteMotion(mode));
            return(motionXToDelta);
        }
Beispiel #10
0
 private static bool ShouldApplyScaleRemove(AppliedOffsetMode mode)
 {
     return(mode == AppliedOffsetMode.SceneOffsetLegacyEditor || mode == AppliedOffsetMode.SceneOffsetLegacy || mode == AppliedOffsetMode.TransformOffsetLegacy);
 }
Beispiel #11
0
        internal static Playable CreatePlayable(PlayableGraph graph, AnimationClip clip, Vector3 positionOffset, Vector3 eulerOffset, bool removeStartOffset, AppliedOffsetMode mode, bool applyFootIK, LoopMode loop)
        {
            if (clip == null || clip.legacy)
            {
                return(Playable.Null);
            }


            var clipPlayable = AnimationClipPlayable.Create(graph, clip);

            clipPlayable.SetRemoveStartOffset(removeStartOffset);
            clipPlayable.SetApplyFootIK(applyFootIK);
            clipPlayable.SetOverrideLoopTime(loop != LoopMode.UseSourceAsset);
            clipPlayable.SetLoopTime(loop == LoopMode.On);

            Playable root = clipPlayable;

            if (ShouldApplyScaleRemove(mode))
            {
                var removeScale = AnimationRemoveScalePlayable.Create(graph, 1);
                graph.Connect(root, 0, removeScale, 0);
                removeScale.SetInputWeight(0, 1.0f);
                root = removeScale;
            }

            if (ShouldApplyOffset(mode, clip))
            {
                var offsetPlayable = AnimationOffsetPlayable.Create(graph, positionOffset, Quaternion.Euler(eulerOffset), 1);
                graph.Connect(root, 0, offsetPlayable, 0);
                offsetPlayable.SetInputWeight(0, 1.0F);
                root = offsetPlayable;
            }

            return(root);
        }
        Playable CreateInfiniteTrackPlayable(PlayableGraph graph, GameObject go, IntervalTree <RuntimeElement> tree, AppliedOffsetMode mode)
        {
            if (m_InfiniteClip == null)
            {
                return(Playable.Null);
            }

            var mixer    = AnimationMixerPlayable.Create(graph, 1);
            var playable = AnimationPlayableAsset.CreatePlayable(graph, m_InfiniteClip, m_InfiniteClipOffsetPosition, m_InfiniteClipOffsetEulerAngles, false, mode, infiniteClipApplyFootIK);

            if (playable.IsValid())
            {
                tree.Add(new InfiniteRuntimeClip(playable));
                graph.Connect(playable, 0, mixer, 0);
                mixer.SetInputWeight(0, 1.0f);
            }

            return(ApplyTrackOffset(graph, mixer, go, mode));
        }