internal override Playable OnCreatePlayableGraph(PlayableGraph graph, GameObject go, IntervalTree <RuntimeElement> tree) { if (base.isSubTrack) { throw new InvalidOperationException("Nested animation tracks should never be asked to create a graph directly"); } List <AnimationTrack> list = new List <AnimationTrack>(); if (this.compilableIsolated) { list.Add(this); } foreach (TrackAsset trackAsset in base.GetChildTracks()) { AnimationTrack animationTrack = trackAsset as AnimationTrack; if (animationTrack != null && animationTrack.compilable) { list.Add(animationTrack); } } AnimationMotionXToDeltaPlayable animationMotionXToDeltaPlayable = AnimationMotionXToDeltaPlayable.Create(graph); AnimationLayerMixerPlayable animationLayerMixerPlayable = AnimationTrack.CreateGroupMixer(graph, go, list.Count); graph.Connect <AnimationLayerMixerPlayable, AnimationMotionXToDeltaPlayable>(animationLayerMixerPlayable, 0, animationMotionXToDeltaPlayable, 0); animationMotionXToDeltaPlayable.SetInputWeight(0, 1f); for (int i = 0; i < list.Count; i++) { Playable source = (!list[i].inClipMode) ? list[i].CreateInfiniteTrackPlayable(graph, go, tree) : this.CompileTrackPlayable(graph, list[i], go, tree); graph.Connect <Playable, AnimationLayerMixerPlayable>(source, 0, animationLayerMixerPlayable, i); animationLayerMixerPlayable.SetInputWeight(i, (float)((!list[i].inClipMode) ? 1 : 0)); if (list[i].applyAvatarMask && list[i].avatarMask != null) { animationLayerMixerPlayable.SetLayerMaskFromAvatarMask((uint)i, list[i].avatarMask); } } return(animationMotionXToDeltaPlayable); }
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); }
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); }
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); }
private void RebuildGraph(Animator animator) { DestroyGraph(); m_Graph = PlayableGraph.Create("PreviewGraph"); m_Graph.SetTimeUpdateMode(DirectorUpdateMode.Manual); m_ClipPlayable = AnimationClipPlayable.Create(m_Graph, state.activeAnimationClip); m_ClipPlayable.SetOverrideLoopTime(true); m_ClipPlayable.SetLoopTime(false); m_ClipPlayable.SetApplyFootIK(false); m_CandidateClipPlayable = AnimationClipPlayable.Create(m_Graph, m_CandidateClip); m_CandidateClipPlayable.SetApplyFootIK(false); IAnimationWindowPreview[] previewComponents = FetchPostProcessComponents(); bool requiresDefaultPose = previewComponents != null && previewComponents.Length > 0; int nInputs = requiresDefaultPose ? 3 : 2; // Create a layer mixer if necessary, we'll connect playable nodes to it after having populated AnimationStream. AnimationLayerMixerPlayable mixer = AnimationLayerMixerPlayable.Create(m_Graph, nInputs); m_GraphRoot = (Playable)mixer; // Populate custom playable preview graph. if (previewComponents != null) { foreach (var component in previewComponents) { m_GraphRoot = component.BuildPreviewGraph(m_Graph, m_GraphRoot); } } // Finish hooking up mixer. int inputIndex = 0; if (requiresDefaultPose) { AnimationMode.RevertPropertyModificationsForGameObject(state.activeRootGameObject); EditorCurveBinding[] streamBindings = AnimationUtility.GetAnimationStreamBindings(state.activeRootGameObject); m_DefaultPose = new AnimationClip() { name = "DefaultPose" }; AnimationWindowUtility.CreateDefaultCurves(state, m_DefaultPose, streamBindings); m_DefaultPosePlayable = AnimationClipPlayable.Create(m_Graph, m_DefaultPose); m_DefaultPosePlayable.SetApplyFootIK(false); mixer.ConnectInput(inputIndex++, m_DefaultPosePlayable, 0, 1.0f); } mixer.ConnectInput(inputIndex++, m_ClipPlayable, 0, 1.0f); mixer.ConnectInput(inputIndex++, m_CandidateClipPlayable, 0, 1.0f); if (animator.applyRootMotion) { var motionX = AnimationMotionXToDeltaPlayable.Create(m_Graph); motionX.SetAbsoluteMotion(true); motionX.SetInputWeight(0, 1.0f); m_Graph.Connect(m_GraphRoot, 0, motionX, 0); m_GraphRoot = (Playable)motionX; } var output = AnimationPlayableOutput.Create(m_Graph, "ouput", animator); output.SetSourcePlayable(m_GraphRoot); output.SetWeight(0.0f); }