first commit

This commit is contained in:
SimonSayeBabu
2025-01-17 13:10:20 +01:00
commit bd1057cec0
16967 changed files with 1048699 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d0cd29fb1ad218b48b814bc3e6d8ac0e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,71 @@
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
class ActivationMixerPlayable : PlayableBehaviour
{
ActivationTrack.PostPlaybackState m_PostPlaybackState;
bool m_BoundGameObjectInitialStateIsActive;
private GameObject m_BoundGameObject;
public static ScriptPlayable<ActivationMixerPlayable> Create(PlayableGraph graph, int inputCount)
{
return ScriptPlayable<ActivationMixerPlayable>.Create(graph, inputCount);
}
public ActivationTrack.PostPlaybackState postPlaybackState
{
get { return m_PostPlaybackState; }
set { m_PostPlaybackState = value; }
}
public override void OnPlayableDestroy(Playable playable)
{
if (m_BoundGameObject == null)
return;
switch (m_PostPlaybackState)
{
case ActivationTrack.PostPlaybackState.Active:
m_BoundGameObject.SetActive(true);
break;
case ActivationTrack.PostPlaybackState.Inactive:
m_BoundGameObject.SetActive(false);
break;
case ActivationTrack.PostPlaybackState.Revert:
m_BoundGameObject.SetActive(m_BoundGameObjectInitialStateIsActive);
break;
case ActivationTrack.PostPlaybackState.LeaveAsIs:
default:
break;
}
}
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
{
if (m_BoundGameObject == null)
{
m_BoundGameObject = playerData as GameObject;
m_BoundGameObjectInitialStateIsActive = m_BoundGameObject != null && m_BoundGameObject.activeSelf;
}
if (m_BoundGameObject == null)
return;
int inputCount = playable.GetInputCount();
bool hasInput = false;
for (int i = 0; i < inputCount; i++)
{
if (playable.GetInputWeight(i) > 0)
{
hasInput = true;
break;
}
}
m_BoundGameObject.SetActive(hasInput);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e165a99d845c10e4ea0f546e542e8684
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
#if UNITY_EDITOR
using System.ComponentModel;
#endif
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
/// <summary>
/// Playable Asset class for Activation Tracks
/// </summary>
#if UNITY_EDITOR
[DisplayName("Activation Clip")]
#endif
class ActivationPlayableAsset : PlayableAsset, ITimelineClipAsset
{
/// <summary>
/// Returns a description of the features supported by activation clips
/// </summary>
public ClipCaps clipCaps { get { return ClipCaps.None; } }
/// <summary>
/// Overrides PlayableAsset.CreatePlayable() to inject needed Playables for an activation asset
/// </summary>
public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
{
return Playable.Create(graph);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fde0d25a170598d46a0b9dc16b4527a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,94 @@
using System;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
/// <summary>
/// Track that can be used to control the active state of a GameObject.
/// </summary>
[Serializable]
[TrackClipType(typeof(ActivationPlayableAsset))]
[TrackBindingType(typeof(GameObject))]
[ExcludeFromPreset]
[TimelineHelpURL(typeof(ActivationTrack))]
public class ActivationTrack : TrackAsset
{
[SerializeField]
PostPlaybackState m_PostPlaybackState = PostPlaybackState.LeaveAsIs;
ActivationMixerPlayable m_ActivationMixer;
/// <summary>
/// Specify what state to leave the GameObject in after the Timeline has finished playing.
/// </summary>
public enum PostPlaybackState
{
/// <summary>
/// Set the GameObject to active.
/// </summary>
Active,
/// <summary>
/// Set the GameObject to Inactive.
/// </summary>
Inactive,
/// <summary>
/// Revert the GameObject to the state in was in before the Timeline was playing.
/// </summary>
Revert,
/// <summary>
/// Leave the GameObject in the state it was when the Timeline was stopped.
/// </summary>
LeaveAsIs
}
internal override bool CanCompileClips()
{
return !hasClips || base.CanCompileClips();
}
/// <summary>
/// Specifies what state to leave the GameObject in after the Timeline has finished playing.
/// </summary>
public PostPlaybackState postPlaybackState
{
get { return m_PostPlaybackState; }
set { m_PostPlaybackState = value; UpdateTrackMode(); }
}
/// <inheritdoc/>
public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
{
var mixer = ActivationMixerPlayable.Create(graph, inputCount);
m_ActivationMixer = mixer.GetBehaviour();
UpdateTrackMode();
return mixer;
}
internal void UpdateTrackMode()
{
if (m_ActivationMixer != null)
m_ActivationMixer.postPlaybackState = m_PostPlaybackState;
}
/// <inheritdoc/>
public override void GatherProperties(PlayableDirector director, IPropertyCollector driver)
{
var gameObject = GetGameObjectBinding(director);
if (gameObject != null)
{
driver.AddFromName(gameObject, "m_IsActive");
}
}
/// <inheritdoc/>
protected override void OnCreateClip(TimelineClip clip)
{
clip.displayName = "Active";
base.OnCreateClip(clip);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 21bf7f712d84d26478ebe6a299f21738
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: de9eb5e2046ffc9448f07e495c436506
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,93 @@
using System.Collections.Generic;
using UnityEngine.Animations;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
// Does a post processing of the weights on an animation track to properly normalize
// the mixer weights so that blending does not bring default poses and subtracks, layers and
// layer graphs blend correctly
class AnimationOutputWeightProcessor : ITimelineEvaluateCallback
{
struct WeightInfo
{
public Playable mixer;
public Playable parentMixer;
public int port;
}
AnimationPlayableOutput m_Output;
AnimationMotionXToDeltaPlayable m_MotionXPlayable;
readonly List<WeightInfo> m_Mixers = new List<WeightInfo>();
public AnimationOutputWeightProcessor(AnimationPlayableOutput output)
{
m_Output = output;
output.SetWeight(0);
FindMixers();
}
void FindMixers()
{
var playable = m_Output.GetSourcePlayable();
var outputPort = m_Output.GetSourceOutputPort();
m_Mixers.Clear();
// only write the final output in playmode. it should always be 1 in editor because we blend to the defaults
FindMixers(playable, outputPort, playable.GetInput(outputPort));
}
// Recursively accumulates mixers.
void FindMixers(Playable parent, int port, Playable node)
{
if (!node.IsValid())
return;
var type = node.GetPlayableType();
if (type == typeof(AnimationMixerPlayable) || type == typeof(AnimationLayerMixerPlayable))
{
// use post fix traversal so children come before parents
int subCount = node.GetInputCount();
for (int j = 0; j < subCount; j++)
{
FindMixers(node, j, node.GetInput(j));
}
// if we encounter a layer mixer, we assume there is nesting occuring
// and we modulate the weight instead of overwriting it.
var weightInfo = new WeightInfo
{
parentMixer = parent,
mixer = node,
port = port,
};
m_Mixers.Add(weightInfo);
}
else
{
var count = node.GetInputCount();
for (var i = 0; i < count; i++)
{
FindMixers(parent, port, node.GetInput(i));
}
}
}
public void Evaluate()
{
float weight = 1;
m_Output.SetWeight(1);
for (int i = 0; i < m_Mixers.Count; i++)
{
var mixInfo = m_Mixers[i];
weight = WeightUtility.NormalizeMixer(mixInfo.mixer);
mixInfo.parentMixer.SetInputWeight(mixInfo.port, weight);
}
// only write the final weight in player/playmode. In editor, we are blending to the appropriate defaults
// the last mixer in the list is the final blend, since the list is composed post-order.
if (Application.isPlaying)
m_Output.SetWeight(weight);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a429b38ee9d48c7408c8870baf406034
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,325 @@
using System.Collections.Generic;
using UnityEngine.Animations;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
/// <summary>
/// A Playable Asset that represents a single AnimationClip clip.
/// </summary>
[System.Serializable, NotKeyable]
public partial class AnimationPlayableAsset : PlayableAsset, ITimelineClipAsset, IPropertyPreview
{
/// <summary>
/// Whether the source AnimationClip loops during playback.
/// </summary>
public enum LoopMode
{
/// <summary>
/// Use the loop time setting from the source AnimationClip.
/// </summary>
[Tooltip("Use the loop time setting from the source AnimationClip.")]
UseSourceAsset = 0,
/// <summary>
/// The source AnimationClip loops during playback.
/// </summary>
[Tooltip("The source AnimationClip loops during playback.")]
On = 1,
/// <summary>
/// The source AnimationClip does not loop during playback.
/// </summary>
[Tooltip("The source AnimationClip does not loop during playback.")]
Off = 2
}
[SerializeField] private AnimationClip m_Clip;
[SerializeField] private Vector3 m_Position = Vector3.zero;
[SerializeField] private Vector3 m_EulerAngles = Vector3.zero;
[SerializeField] private bool m_UseTrackMatchFields = true;
[SerializeField] private MatchTargetFields m_MatchTargetFields = MatchTargetFieldConstants.All;
[SerializeField] private bool m_RemoveStartOffset = true; // set by animation track prior to compilation
[SerializeField] private bool m_ApplyFootIK = true;
[SerializeField] private LoopMode m_Loop = LoopMode.UseSourceAsset;
#if UNITY_EDITOR
private AnimationOffsetPlayable m_AnimationOffsetPlayable;
#endif
/// <summary>
/// The translational offset of the clip
/// </summary>
public Vector3 position
{
get
{
return m_Position;
}
set
{
m_Position = value;
#if UNITY_EDITOR
if (m_AnimationOffsetPlayable.IsValid())
m_AnimationOffsetPlayable.SetPosition(position);
#endif
}
}
/// <summary>
/// The rotational offset of the clip, expressed as a Quaternion
/// </summary>
public Quaternion rotation
{
get
{
return Quaternion.Euler(m_EulerAngles);
}
set
{
m_EulerAngles = value.eulerAngles;
#if UNITY_EDITOR
if (m_AnimationOffsetPlayable.IsValid())
m_AnimationOffsetPlayable.SetRotation(value);
#endif
}
}
/// <summary>
/// The rotational offset of the clip, expressed in Euler angles
/// </summary>
public Vector3 eulerAngles
{
get { return m_EulerAngles; }
set
{
m_EulerAngles = value;
#if UNITY_EDITOR
if (m_AnimationOffsetPlayable.IsValid())
m_AnimationOffsetPlayable.SetRotation(rotation);
#endif
}
}
/// <summary>
/// Specifies whether to use offset matching options as defined by the track.
/// </summary>
public bool useTrackMatchFields
{
get { return m_UseTrackMatchFields; }
set { m_UseTrackMatchFields = value; }
}
/// <summary>
/// Specifies which fields should be matched when aligning offsets.
/// </summary>
public MatchTargetFields matchTargetFields
{
get { return m_MatchTargetFields; }
set { m_MatchTargetFields = value; }
}
/// <summary>
/// Whether to make the animation clip play relative to its first keyframe.
/// </summary>
/// <remarks>
/// This option only applies to animation clips that animate Transform components.
/// </remarks>
public bool removeStartOffset
{
get { return m_RemoveStartOffset; }
set { m_RemoveStartOffset = value; }
}
/// <summary>
/// Enable to apply foot IK to the AnimationClip when the target is humanoid.
/// </summary>
public bool applyFootIK
{
get { return m_ApplyFootIK; }
set { m_ApplyFootIK = value; }
}
/// <summary>
/// Whether the source AnimationClip loops during playback
/// </summary>
public LoopMode loop
{
get { return m_Loop; }
set { m_Loop = value; }
}
internal bool hasRootTransforms
{
get { return m_Clip != null && HasRootTransforms(m_Clip); }
}
// used for legacy 'scene' mode.
internal AppliedOffsetMode appliedOffsetMode { get; set; }
/// <summary>
/// The source animation clip
/// </summary>
public AnimationClip clip
{
get { return m_Clip; }
set
{
if (value != null)
name = "AnimationPlayableAsset of " + value.name;
m_Clip = value;
}
}
/// <summary>
/// Returns the duration required to play the animation clip exactly once
/// </summary>
public override double duration
{
get
{
double length = TimeUtility.GetAnimationClipLength(clip);
if (length < float.Epsilon)
return base.duration;
return length;
}
}
/// <summary>
/// Returns a description of the PlayableOutputs that may be created for this asset.
/// </summary>
public override IEnumerable<PlayableBinding> outputs
{
get { yield return AnimationPlayableBinding.Create(name, this); }
}
/// <summary>
/// Creates the root of a Playable subgraph to play the animation clip.
/// </summary>
/// <param name="graph">PlayableGraph that will own the playable</param>
/// <param name="go">The gameobject that triggered the graph build</param>
/// <returns>The root playable of the subgraph</returns>
public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
{
Playable root = CreatePlayable(graph, m_Clip, position, eulerAngles, removeStartOffset, appliedOffsetMode, applyFootIK, m_Loop);
#if UNITY_EDITOR
m_AnimationOffsetPlayable = AnimationOffsetPlayable.Null;
if (root.IsValid() && root.IsPlayableOfType<AnimationOffsetPlayable>())
{
m_AnimationOffsetPlayable = (AnimationOffsetPlayable)root;
}
LiveLink();
#endif
return root;
}
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;
}
private static bool ShouldApplyOffset(AppliedOffsetMode mode, AnimationClip clip)
{
if (mode == AppliedOffsetMode.NoRootTransform || mode == AppliedOffsetMode.SceneOffsetLegacy)
return false;
return HasRootTransforms(clip);
}
private static bool ShouldApplyScaleRemove(AppliedOffsetMode mode)
{
return mode == AppliedOffsetMode.SceneOffsetLegacyEditor || mode == AppliedOffsetMode.SceneOffsetLegacy || mode == AppliedOffsetMode.TransformOffsetLegacy;
}
#if UNITY_EDITOR
public void LiveLink()
{
if (m_AnimationOffsetPlayable.IsValid())
{
m_AnimationOffsetPlayable.SetPosition(position);
m_AnimationOffsetPlayable.SetRotation(rotation);
}
}
#endif
/// <summary>
/// Returns the capabilities of TimelineClips that contain a AnimationPlayableAsset
/// </summary>
public ClipCaps clipCaps
{
get
{
var caps = ClipCaps.Extrapolation | ClipCaps.SpeedMultiplier | ClipCaps.Blending;
if (m_Clip != null && (m_Loop != LoopMode.Off) && (m_Loop != LoopMode.UseSourceAsset || m_Clip.isLooping))
caps |= ClipCaps.Looping;
// empty clips don't support clip in. This allows trim operations to simply become move operations
if (m_Clip != null && !m_Clip.empty)
caps |= ClipCaps.ClipIn;
return caps;
}
}
/// <summary>
/// Resets the offsets to default values
/// </summary>
public void ResetOffsets()
{
position = Vector3.zero;
eulerAngles = Vector3.zero;
}
/// <inheritdoc/>
public void GatherProperties(PlayableDirector director, IPropertyCollector driver)
{
driver.AddFromClip(m_Clip);
}
internal static bool HasRootTransforms(AnimationClip clip)
{
if (clip == null || clip.empty)
return false;
return clip.hasRootMotion || clip.hasGenericRootTransform || clip.hasMotionCurves || clip.hasRootCurves;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 030f85c3f73729f4f976f66ffb23b875
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,57 @@
using System.Collections.Generic;
using UnityEngine.Animations;
#if !UNITY_2020_2_OR_NEWER
using UnityEngine.Experimental.Animations;
#endif
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
class AnimationPreviewUpdateCallback : ITimelineEvaluateCallback
{
AnimationPlayableOutput m_Output;
PlayableGraph m_Graph;
List<IAnimationWindowPreview> m_PreviewComponents;
public AnimationPreviewUpdateCallback(AnimationPlayableOutput output)
{
m_Output = output;
Playable playable = m_Output.GetSourcePlayable();
if (playable.IsValid())
{
m_Graph = playable.GetGraph();
}
}
public void Evaluate()
{
if (!m_Graph.IsValid())
return;
if (m_PreviewComponents == null)
FetchPreviewComponents();
foreach (var component in m_PreviewComponents)
{
if (component != null)
{
component.UpdatePreviewGraph(m_Graph);
}
}
}
private void FetchPreviewComponents()
{
m_PreviewComponents = new List<IAnimationWindowPreview>();
var animator = m_Output.GetTarget();
if (animator == null)
return;
var gameObject = animator.gameObject;
m_PreviewComponents.AddRange(gameObject.GetComponents<IAnimationWindowPreview>());
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 755e3e942f7784d458bddba421c0bb72
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d21dcc2386d650c4597f3633c75a1f98
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
namespace UnityEngine.Timeline
{
interface ICurvesOwner
{
AnimationClip curves { get; }
bool hasCurves { get; }
double duration { get; }
void CreateCurves(string curvesClipName);
string defaultCurvesName { get; }
Object asset { get; }
Object assetOwner { get; }
TrackAsset targetTrack { get; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 89b31ff5ca0a5eb4797ac65d43949807
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0c04c8cb23b78e04492e0f310cdee93e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
using System;
namespace UnityEngine.Timeline
{
partial class AnimationPlayableAsset : ISerializationCallbackReceiver
{
enum Versions
{
Initial = 0,
RotationAsEuler = 1,
}
static readonly int k_LatestVersion = (int)Versions.RotationAsEuler;
[SerializeField, HideInInspector] int m_Version;
[SerializeField, Obsolete("Use m_RotationEuler Instead", false), HideInInspector]
private Quaternion m_Rotation = Quaternion.identity; // deprecated. now saves in euler angles
/// <summary>
/// Called before Unity serializes this object.
/// </summary>
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
m_Version = k_LatestVersion;
}
/// <summary>
/// Called after Unity deserializes this object.
/// </summary>
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
if (m_Version < k_LatestVersion)
{
OnUpgradeFromVersion(m_Version); //upgrade derived classes
}
}
void OnUpgradeFromVersion(int oldVersion)
{
if (oldVersion < (int)Versions.RotationAsEuler)
AnimationPlayableAssetUpgrade.ConvertRotationToEuler(this);
}
static class AnimationPlayableAssetUpgrade
{
public static void ConvertRotationToEuler(AnimationPlayableAsset asset)
{
#pragma warning disable 618
asset.m_EulerAngles = asset.m_Rotation.eulerAngles;
#pragma warning restore 618
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6773203120b27984d9a8572fa3564f03
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,122 @@
using System;
using System.ComponentModel;
namespace UnityEngine.Timeline
{
partial class AnimationTrack
{
// 649 is value is only assigned to. they can be updated from old files being serialized
#pragma warning disable 649
//fields that are used for upgrading should be put here, ideally as read-only
[SerializeField, Obsolete("Use m_InfiniteClipOffsetEulerAngles Instead", false), HideInInspector]
Quaternion m_OpenClipOffsetRotation = Quaternion.identity;
[SerializeField, Obsolete("Use m_RotationEuler Instead", false), HideInInspector]
Quaternion m_Rotation = Quaternion.identity;
[SerializeField, Obsolete("Use m_RootTransformOffsetMode", false), HideInInspector]
bool m_ApplyOffsets;
#pragma warning restore 649
/// <summary>
/// Translation offset of a track in infinite mode.
/// This property is obsolete. Use <see cref="UnityEngine.Timeline.AnimationTrack.infiniteClipOffsetPosition"/> instead.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("openClipOffsetPosition has been deprecated. Use infiniteClipOffsetPosition instead. (UnityUpgradable) -> infiniteClipOffsetPosition", true)]
public Vector3 openClipOffsetPosition
{
get { return infiniteClipOffsetPosition; }
set { infiniteClipOffsetPosition = value; }
}
/// <summary>
/// Rotation offset of a track in infinite mode.
/// This property is obsolete. Use <see cref="UnityEngine.Timeline.AnimationTrack.infiniteClipOffsetRotation"/> instead.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("openClipOffsetRotation has been deprecated. Use infiniteClipOffsetRotation instead. (UnityUpgradable) -> infiniteClipOffsetRotation", true)]
public Quaternion openClipOffsetRotation
{
get { return infiniteClipOffsetRotation; }
set { infiniteClipOffsetRotation = value; }
}
/// <summary>
/// Euler angle representation of the rotation offset of the track when in infinite mode.
/// This property is obsolete. Use <see cref="UnityEngine.Timeline.AnimationTrack.infiniteClipOffsetEulerAngles"/> instead.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("openClipOffsetEulerAngles has been deprecated. Use infiniteClipOffsetEulerAngles instead. (UnityUpgradable) -> infiniteClipOffsetEulerAngles", true)]
public Vector3 openClipOffsetEulerAngles
{
get { return infiniteClipOffsetEulerAngles; }
set { infiniteClipOffsetEulerAngles = value; }
}
/// <summary>
/// Saved state of pre-extrapolation for clips converted to infinite mode.
/// This property is obsolete. Use <see cref="UnityEngine.Timeline.AnimationTrack.infiniteClipPreExtrapolation"/> instead.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("openClipPreExtrapolation has been deprecated. Use infiniteClipPreExtrapolation instead. (UnityUpgradable) -> infiniteClipPreExtrapolation", true)]
public TimelineClip.ClipExtrapolation openClipPreExtrapolation
{
get { return infiniteClipPreExtrapolation; }
set { infiniteClipPreExtrapolation = value; }
}
/// <summary>
/// Saved state of post-extrapolation for clips converted to infinite mode.
/// This property is obsolete. Use <see cref="UnityEngine.Timeline.AnimationTrack.infiniteClipPostExtrapolation"/> instead.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("openClipPostExtrapolation has been deprecated. Use infiniteClipPostExtrapolation instead. (UnityUpgradable) -> infiniteClipPostExtrapolation", true)]
public TimelineClip.ClipExtrapolation openClipPostExtrapolation
{
get { return infiniteClipPostExtrapolation; }
set { infiniteClipPostExtrapolation = value; }
}
internal override void OnUpgradeFromVersion(int oldVersion)
{
if (oldVersion < (int)Versions.RotationAsEuler)
AnimationTrackUpgrade.ConvertRotationsToEuler(this);
if (oldVersion < (int)Versions.RootMotionUpgrade)
AnimationTrackUpgrade.ConvertRootMotion(this);
if (oldVersion < (int)Versions.AnimatedTrackProperties)
AnimationTrackUpgrade.ConvertInfiniteTrack(this);
}
// 612 is Property is Obsolete
// 618 is Field is Obsolete
#pragma warning disable 612, 618
static class AnimationTrackUpgrade
{
public static void ConvertRotationsToEuler(AnimationTrack track)
{
track.m_EulerAngles = track.m_Rotation.eulerAngles;
track.m_InfiniteClipOffsetEulerAngles = track.m_OpenClipOffsetRotation.eulerAngles;
}
public static void ConvertRootMotion(AnimationTrack track)
{
track.m_TrackOffset = TrackOffset.Auto; // loaded tracks should use legacy mode
// reset offsets if not applied
if (!track.m_ApplyOffsets)
{
track.m_Position = Vector3.zero;
track.m_EulerAngles = Vector3.zero;
}
}
public static void ConvertInfiniteTrack(AnimationTrack track)
{
track.m_InfiniteClip = track.m_AnimClip;
track.m_AnimClip = null;
}
}
#pragma warning restore 612, 618
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3b0c53b13a1539949b3b212e049151d1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
namespace UnityEngine.Timeline
{
partial class TimelineClip
{
enum Versions
{
Initial = 0,
ClipInFromGlobalToLocal = 1
}
const int k_LatestVersion = (int)Versions.ClipInFromGlobalToLocal;
[SerializeField, HideInInspector] int m_Version;
//fields that are used for upgrading should be put here, ideally as read-only
void UpgradeToLatestVersion()
{
if (m_Version < (int)Versions.ClipInFromGlobalToLocal)
{
TimelineClipUpgrade.UpgradeClipInFromGlobalToLocal(this);
}
}
static class TimelineClipUpgrade
{
// version 0->1, clipIn move from global to local
public static void UpgradeClipInFromGlobalToLocal(TimelineClip clip)
{
// case 936751 -- clipIn was serialized in global, not local offset
if (clip.m_ClipIn > 0 && clip.m_TimeScale > float.Epsilon)
clip.m_ClipIn *= clip.m_TimeScale;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6a4f0c91a28ece04198b200dd55145d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
namespace UnityEngine.Timeline
{
partial class TimelineAsset
{
enum Versions
{
Initial = 0
}
const int k_LatestVersion = (int)Versions.Initial;
[SerializeField, HideInInspector] int m_Version;
//fields that are used for upgrading should be put here, ideally as read-only
void UpgradeToLatestVersion()
{ }
//upgrade code should go into this class
static class TimelineAssetUpgrade
{ }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 95c91abdcc1ea03458c2ea4e9626a5d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,89 @@
using System;
using UnityEngine.Serialization;
namespace UnityEngine.Timeline
{
partial class TrackAsset : ISerializationCallbackReceiver
{
internal enum Versions
{
Initial = 0,
RotationAsEuler = 1,
RootMotionUpgrade = 2,
AnimatedTrackProperties = 3
}
const int k_LatestVersion = (int)Versions.AnimatedTrackProperties;
[SerializeField, HideInInspector] int m_Version;
[Obsolete("Please use m_InfiniteClip (on AnimationTrack) instead.", false)]
[SerializeField, HideInInspector, FormerlySerializedAs("m_animClip")]
internal AnimationClip m_AnimClip;
/// <summary>
/// Called before a track is serialized.
/// </summary>
protected virtual void OnBeforeTrackSerialize() { }
/// <summary>
/// Called after a track has been deserialized.
/// </summary>
protected virtual void OnAfterTrackDeserialize() { }
internal virtual void OnUpgradeFromVersion(int oldVersion) { }
/// <summary>
/// Called before Unity serializes this object.
/// </summary>
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
m_Version = k_LatestVersion;
//make sure children are correctly parented
if (m_Children != null)
{
for (var i = m_Children.Count - 1; i >= 0; i--)
{
var asset = m_Children[i] as TrackAsset;
if (asset != null && asset.parent != this)
asset.parent = this;
}
}
OnBeforeTrackSerialize();
}
/// <summary>
/// Called after Unity deserializes this object.
/// </summary>
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
// Clear the clip cache when a deserialize is performed, or
// we can get out of sync when performing Undo
m_ClipsCache = null;
Invalidate();
if (m_Version < k_LatestVersion)
{
UpgradeToLatestVersion(); //upgrade TrackAsset
OnUpgradeFromVersion(m_Version); //upgrade derived classes
}
foreach (var marker in GetMarkers())
{
marker.Initialize(this);
}
OnAfterTrackDeserialize();
}
//fields that are used for upgrading should be put here, ideally as read-only
void UpgradeToLatestVersion()
{ }
//upgrade code should go into this class
static class TrackAssetUpgrade
{ }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c68f34993bfe85e489158a29c99a20b5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ec817e5e5781e0a4983a1dc8875d1974
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,46 @@
#if UNITY_EDITOR && UNITY_2021_1_OR_NEWER
#define CAN_USE_CUSTOM_HELP_URL
#endif
using System;
using System.Diagnostics;
using UnityEngine;
namespace UnityEngine.Timeline
{
#if CAN_USE_CUSTOM_HELP_URL
using UnityEditor.PackageManager;
[Conditional("UNITY_EDITOR")]
class TimelineHelpURLAttribute : HelpURLAttribute
{
const string k_BaseURL = "https://docs.unity3d.com/Packages/com.unity.timeline@";
const string k_MidURL = "/api/";
const string k_EndURL = ".html";
const string k_FallbackVersion = "latest";
static readonly string k_PackageVersion;
static TimelineHelpURLAttribute()
{
PackageInfo packageInfo = PackageInfo.FindForAssembly(typeof(TimelineAsset).Assembly);
k_PackageVersion = packageInfo == null ? k_FallbackVersion : packageInfo.version.Substring(0, 3);
}
public TimelineHelpURLAttribute(Type type)
: base(HelpURL(type)) {}
static string HelpURL(Type type)
{
return $"{k_BaseURL}{k_PackageVersion}{k_MidURL}{type.FullName}{k_EndURL}";
}
}
#else //HelpURL attribute is `sealed` in previous Unity versions
[Conditional("UNITY_EDITOR")]
class TimelineHelpURLAttribute : Attribute
{
public TimelineHelpURLAttribute(Type type) { }
}
#endif
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c35b6ea5f1d7cd74eac79413eb70670c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
using System;
using UnityEngine;
namespace UnityEngine.Timeline
{
/// <summary>
/// Attribute used to specify the color of the track and its clips inside the Timeline Editor.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class TrackColorAttribute : Attribute
{
Color m_Color;
/// <summary>
///
/// </summary>
public Color color
{
get { return m_Color; }
}
/// <summary>
/// Specify the track color using [0-1] R,G,B values.
/// </summary>
/// <param name="r">Red value [0-1].</param>
/// <param name="g">Green value [0-1].</param>
/// <param name="b">Blue value [0-1].</param>
public TrackColorAttribute(float r, float g, float b)
{
m_Color = new Color(r, g, b);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c3d52cc5c46d7946a920e21901ff38e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d19b75372f4e44d4fa4b2cffbb54124b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
using System;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
[Serializable]
[NotKeyable]
class AudioClipProperties : PlayableBehaviour
{
[Range(0.0f, 1.0f)]
public float volume = 1.0f;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0d60a406ab64c434e9d731914e11a51e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,45 @@
using System;
using UnityEngine.Audio;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
[Serializable]
class AudioMixerProperties : PlayableBehaviour
{
[Range(0.0f, 1.0f)]
public float volume = 1.0f;
[Range(-1.0f, 1.0f)]
public float stereoPan = 0.0f;
[Range(0.0f, 1.0f)]
public float spatialBlend = 0.0f;
public override void PrepareFrame(Playable playable, FrameData info)
{
if (!playable.IsValid() || !playable.IsPlayableOfType<AudioMixerPlayable>())
return;
var inputCount = playable.GetInputCount();
for (int i = 0; i < inputCount; ++i)
{
if (playable.GetInputWeight(i) > 0.0f)
{
var input = playable.GetInput(i);
if (input.IsValid() && input.IsPlayableOfType<AudioClipPlayable>())
{
var audioClipPlayable = (AudioClipPlayable)input;
var audioClipProperties = input.GetHandle().GetObject<AudioClipProperties>();
audioClipPlayable.SetVolume(Mathf.Clamp01(volume * audioClipProperties.volume));
audioClipPlayable.SetStereoPan(Mathf.Clamp(stereoPan, -1.0f, 1.0f));
audioClipPlayable.SetSpatialBlend(Mathf.Clamp01(spatialBlend));
}
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8c4a920f001ca64680ed6fdb52d1753
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using UnityEngine.Audio;
#if UNITY_EDITOR
using System.ComponentModel;
#endif
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
/// <summary>
/// PlayableAsset wrapper for an AudioClip in Timeline.
/// </summary>
[Serializable]
#if UNITY_EDITOR
[DisplayName("Audio Clip")]
#endif
public class AudioPlayableAsset : PlayableAsset, ITimelineClipAsset
{
[SerializeField] AudioClip m_Clip;
#pragma warning disable 649 //Field is never assigned to and will always have its default value
[SerializeField] bool m_Loop;
[SerializeField, HideInInspector] float m_bufferingTime = 0.1f;
[SerializeField] AudioClipProperties m_ClipProperties = new AudioClipProperties();
// the amount of time to give the clip to load prior to it's start time
internal float bufferingTime
{
get { return m_bufferingTime; }
set { m_bufferingTime = value; }
}
#if UNITY_EDITOR
Playable m_LiveClipPlayable = Playable.Null;
#endif
/// <summary>
/// The audio clip to be played
/// </summary>
public AudioClip clip
{
get { return m_Clip; }
set { m_Clip = value; }
}
/// <summary>
/// Whether the audio clip loops.
/// </summary>
/// <remarks>
/// Use this to loop the audio clip when the duration of the timeline clip exceeds that of the audio clip.
/// </remarks>
public bool loop
{
get { return m_Loop; }
set { m_Loop = value; }
}
/// <summary>
/// Returns the duration required to play the audio clip exactly once
/// </summary>
public override double duration
{
get
{
if (m_Clip == null)
return base.duration;
// use this instead of length to avoid rounding precision errors,
return (double)m_Clip.samples / m_Clip.frequency;
}
}
/// <summary>
/// Returns a description of the PlayableOutputs that may be created for this asset.
/// </summary>
public override IEnumerable<PlayableBinding> outputs
{
get { yield return AudioPlayableBinding.Create(name, this); }
}
/// <summary>
/// Creates the root of a Playable subgraph to play the audio clip.
/// </summary>
/// <param name="graph">PlayableGraph that will own the playable</param>
/// <param name="go">The GameObject that triggered the graph build</param>
/// <returns>The root playable of the subgraph</returns>
public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
{
if (m_Clip == null)
return Playable.Null;
var audioClipPlayable = AudioClipPlayable.Create(graph, m_Clip, m_Loop);
audioClipPlayable.GetHandle().SetScriptInstance(m_ClipProperties.Clone());
#if UNITY_EDITOR
m_LiveClipPlayable = audioClipPlayable;
#endif
return audioClipPlayable;
}
/// <summary>
/// Returns the capabilities of TimelineClips that contain an AudioPlayableAsset
/// </summary>
public ClipCaps clipCaps
{
get
{
return ClipCaps.ClipIn |
ClipCaps.SpeedMultiplier |
ClipCaps.Blending |
(m_Loop ? ClipCaps.Looping : ClipCaps.None);
}
}
#if UNITY_EDITOR
internal void LiveLink()
{
if (!m_LiveClipPlayable.IsValid())
return;
var audioMixerProperties = m_LiveClipPlayable.GetHandle().GetObject<AudioClipProperties>();
if (audioMixerProperties == null)
return;
audioMixerProperties.volume = m_ClipProperties.volume;
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4f10dd60657c6004587f237a7e90f8e4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using UnityEngine.Audio;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
/// <summary>
/// A Timeline track that can play AudioClips.
/// </summary>
[Serializable]
[TrackClipType(typeof(AudioPlayableAsset), false)]
[TrackBindingType(typeof(AudioSource))]
[ExcludeFromPreset]
[TimelineHelpURL(typeof(AudioTrack))]
public class AudioTrack : TrackAsset
{
[SerializeField]
AudioMixerProperties m_TrackProperties = new AudioMixerProperties();
#if UNITY_EDITOR
Playable m_LiveMixerPlayable = Playable.Null;
#endif
/// <summary>
/// Create an TimelineClip for playing an AudioClip on this track.
/// </summary>
/// <param name="clip">The audio clip to play</param>
/// <returns>A TimelineClip with an AudioPlayableAsset asset.</returns>
public TimelineClip CreateClip(AudioClip clip)
{
if (clip == null)
return null;
var newClip = CreateDefaultClip();
var audioAsset = newClip.asset as AudioPlayableAsset;
if (audioAsset != null)
audioAsset.clip = clip;
newClip.duration = clip.length;
newClip.displayName = clip.name;
return newClip;
}
internal override Playable CompileClips(PlayableGraph graph, GameObject go, IList<TimelineClip> timelineClips, IntervalTree<RuntimeElement> tree)
{
var clipBlender = AudioMixerPlayable.Create(graph, timelineClips.Count);
#if UNITY_EDITOR
clipBlender.GetHandle().SetScriptInstance(m_TrackProperties.Clone());
m_LiveMixerPlayable = clipBlender;
#else
if (hasCurves)
clipBlender.GetHandle().SetScriptInstance(m_TrackProperties.Clone());
#endif
for (int i = 0; i < timelineClips.Count; i++)
{
var c = timelineClips[i];
var asset = c.asset as PlayableAsset;
if (asset == null)
continue;
var buffer = 0.1f;
var audioAsset = c.asset as AudioPlayableAsset;
if (audioAsset != null)
buffer = audioAsset.bufferingTime;
var source = asset.CreatePlayable(graph, go);
if (!source.IsValid())
continue;
if (source.IsPlayableOfType<AudioClipPlayable>())
{
// Enforce initial values on all clips
var audioClipPlayable = (AudioClipPlayable)source;
var audioClipProperties = audioClipPlayable.GetHandle().GetObject<AudioClipProperties>();
audioClipPlayable.SetVolume(Mathf.Clamp01(m_TrackProperties.volume * audioClipProperties.volume));
audioClipPlayable.SetStereoPan(Mathf.Clamp(m_TrackProperties.stereoPan, -1.0f, 1.0f));
audioClipPlayable.SetSpatialBlend(Mathf.Clamp01(m_TrackProperties.spatialBlend));
}
tree.Add(new ScheduleRuntimeClip(c, source, clipBlender, buffer));
graph.Connect(source, 0, clipBlender, i);
source.SetSpeed(c.timeScale);
source.SetDuration(c.extrapolatedDuration);
clipBlender.SetInputWeight(source, 1.0f);
}
ConfigureTrackAnimation(tree, go, clipBlender);
return clipBlender;
}
/// <inheritdoc/>
public override IEnumerable<PlayableBinding> outputs
{
get { yield return AudioPlayableBinding.Create(name, this); }
}
#if UNITY_EDITOR
internal void LiveLink()
{
if (!m_LiveMixerPlayable.IsValid())
return;
var audioMixerProperties = m_LiveMixerPlayable.GetHandle().GetObject<AudioMixerProperties>();
if (audioMixerProperties == null)
return;
audioMixerProperties.volume = m_TrackProperties.volume;
audioMixerProperties.stereoPan = m_TrackProperties.stereoPan;
audioMixerProperties.spatialBlend = m_TrackProperties.spatialBlend;
}
#endif
void OnValidate()
{
m_TrackProperties.volume = Mathf.Clamp01(m_TrackProperties.volume);
m_TrackProperties.stereoPan = Mathf.Clamp(m_TrackProperties.stereoPan, -1.0f, 1.0f);
m_TrackProperties.spatialBlend = Mathf.Clamp01(m_TrackProperties.spatialBlend);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8b22792c3b570444eb18cb78c2af3a74
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
using System;
namespace UnityEngine.Timeline
{
/// <summary>
/// Describes the timeline features supported by a clip
/// </summary>
[Flags]
public enum ClipCaps
{
/// <summary>
/// No features are supported.
/// </summary>
None = 0,
/// <summary>
/// The clip supports loops.
/// </summary>
Looping = 1 << 0,
/// <summary>
/// The clip supports clip extrapolation.
/// </summary>
Extrapolation = 1 << 1,
/// <summary>
/// The clip supports initial local times greater than zero.
/// </summary>
ClipIn = 1 << 2,
/// <summary>
/// The clip supports time scaling.
/// </summary>
SpeedMultiplier = 1 << 3,
/// <summary>
/// The clip supports blending between clips.
/// </summary>
Blending = 1 << 4,
/// <summary>
/// The clip supports time scaling, and sets the default trim mode in the editor to scale the clip
/// (speed multiplier) when the start/end of the clip is trimmed.
/// </summary>
AutoScale = 1 << 5 | SpeedMultiplier,
/// <summary>
/// All features are supported.
/// </summary>
All = ~None
}
static class TimelineClipCapsExtensions
{
public static bool SupportsLooping(this TimelineClip clip)
{
return clip != null && (clip.clipCaps & ClipCaps.Looping) != ClipCaps.None;
}
public static bool SupportsExtrapolation(this TimelineClip clip)
{
return clip != null && (clip.clipCaps & ClipCaps.Extrapolation) != ClipCaps.None;
}
public static bool SupportsClipIn(this TimelineClip clip)
{
return clip != null && (clip.clipCaps & ClipCaps.ClipIn) != ClipCaps.None;
}
public static bool SupportsSpeedMultiplier(this TimelineClip clip)
{
return clip != null && (clip.clipCaps & ClipCaps.SpeedMultiplier) != ClipCaps.None;
}
public static bool SupportsBlending(this TimelineClip clip)
{
return clip != null && (clip.clipCaps & ClipCaps.Blending) != ClipCaps.None;
}
public static bool HasAll(this ClipCaps caps, ClipCaps flags)
{
return (caps & flags) == flags;
}
public static bool HasAny(this ClipCaps caps, ClipCaps flags)
{
return (caps & flags) != 0;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 667a99762bdf5484fbaa02573fd396e2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ea998292f45ea494d9e100f5f6362f91
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,440 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
/// <summary>
/// Playable Asset that generates playables for controlling time-related elements on a GameObject.
/// </summary>
[Serializable]
[NotKeyable]
public class ControlPlayableAsset : PlayableAsset, IPropertyPreview, ITimelineClipAsset
{
const int k_MaxRandInt = 10000;
static readonly List<PlayableDirector> k_EmptyDirectorsList = new List<PlayableDirector>(0);
static readonly List<ParticleSystem> k_EmptyParticlesList = new List<ParticleSystem>(0);
static readonly HashSet<ParticleSystem> s_SubEmitterCollector = new HashSet<ParticleSystem>();
/// <summary>
/// GameObject in the scene to control, or the parent of the instantiated prefab.
/// </summary>
[SerializeField] public ExposedReference<GameObject> sourceGameObject;
/// <summary>
/// Prefab object that will be instantiated.
/// </summary>
[SerializeField] public GameObject prefabGameObject;
/// <summary>
/// Indicates whether Particle Systems will be controlled.
/// </summary>
[SerializeField] public bool updateParticle = true;
/// <summary>
/// Random seed to supply particle systems that are set to use autoRandomSeed
/// </summary>
/// <remarks>
/// This is used to maintain determinism when playing back in timeline. Sub emitters will be assigned incrementing random seeds to maintain determinism and distinction.
/// </remarks>
[SerializeField] public uint particleRandomSeed;
/// <summary>
/// Indicates whether playableDirectors are controlled.
/// </summary>
[SerializeField] public bool updateDirector = true;
/// <summary>
/// Indicates whether Monobehaviours implementing ITimeControl will be controlled.
/// </summary>
[SerializeField] public bool updateITimeControl = true;
/// <summary>
/// Indicates whether to search the entire hierarchy for controllable components.
/// </summary>
[SerializeField] public bool searchHierarchy;
/// <summary>
/// Indicate whether GameObject activation is controlled
/// </summary>
[SerializeField] public bool active = true;
/// <summary>
/// Indicates the active state of the GameObject when Timeline is stopped.
/// </summary>
[SerializeField] public ActivationControlPlayable.PostPlaybackState postPlayback = ActivationControlPlayable.PostPlaybackState.Revert;
PlayableAsset m_ControlDirectorAsset;
double m_Duration = PlayableBinding.DefaultDuration;
bool m_SupportLoop;
private static HashSet<PlayableDirector> s_ProcessedDirectors = new HashSet<PlayableDirector>();
private static HashSet<GameObject> s_CreatedPrefabs = new HashSet<GameObject>();
// does the last instance created control directors and/or particles
internal bool controllingDirectors { get; private set; }
internal bool controllingParticles { get; private set; }
/// <summary>
/// This function is called when the object is loaded.
/// </summary>
public void OnEnable()
{
// can't be set in a constructor
if (particleRandomSeed == 0)
particleRandomSeed = (uint)Random.Range(1, k_MaxRandInt);
}
/// <summary>
/// Returns the duration in seconds needed to play the underlying director or particle system exactly once.
/// </summary>
public override double duration { get { return m_Duration; } }
/// <summary>
/// Returns the capabilities of TimelineClips that contain a ControlPlayableAsset
/// </summary>
public ClipCaps clipCaps
{
get { return ClipCaps.ClipIn | ClipCaps.SpeedMultiplier | (m_SupportLoop ? ClipCaps.Looping : ClipCaps.None); }
}
/// <summary>
/// Creates the root of a Playable subgraph to control the contents of the game object.
/// </summary>
/// <param name="graph">PlayableGraph that will own the playable</param>
/// <param name="go">The GameObject that triggered the graph build</param>
/// <returns>The root playable of the subgraph</returns>
public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
{
// case 989856
if (prefabGameObject != null)
{
if (s_CreatedPrefabs.Contains(prefabGameObject))
{
Debug.LogWarningFormat("Control Track Clip ({0}) is causing a prefab to instantiate itself recursively. Aborting further instances.", name);
return Playable.Create(graph);
}
s_CreatedPrefabs.Add(prefabGameObject);
}
Playable root = Playable.Null;
var playables = new List<Playable>();
GameObject sourceObject = sourceGameObject.Resolve(graph.GetResolver());
if (prefabGameObject != null)
{
Transform parenTransform = sourceObject != null ? sourceObject.transform : null;
var controlPlayable = PrefabControlPlayable.Create(graph, prefabGameObject, parenTransform);
sourceObject = controlPlayable.GetBehaviour().prefabInstance;
playables.Add(controlPlayable);
}
m_Duration = PlayableBinding.DefaultDuration;
m_SupportLoop = false;
controllingParticles = false;
controllingDirectors = false;
if (sourceObject != null)
{
var directors = updateDirector ? GetComponent<PlayableDirector>(sourceObject) : k_EmptyDirectorsList;
var particleSystems = updateParticle ? GetControllableParticleSystems(sourceObject) : k_EmptyParticlesList;
// update the duration and loop values (used for UI purposes) here
// so they are tied to the latest gameObject bound
UpdateDurationAndLoopFlag(directors, particleSystems);
var director = go.GetComponent<PlayableDirector>();
if (director != null)
m_ControlDirectorAsset = director.playableAsset;
if (go == sourceObject && prefabGameObject == null)
{
Debug.LogWarningFormat("Control Playable ({0}) is referencing the same PlayableDirector component than the one in which it is playing.", name);
active = false;
if (!searchHierarchy)
updateDirector = false;
}
if (active)
CreateActivationPlayable(sourceObject, graph, playables);
if (updateDirector)
SearchHierarchyAndConnectDirector(directors, graph, playables, prefabGameObject != null);
if (updateParticle)
SearchHierarchyAndConnectParticleSystem(particleSystems, graph, playables);
if (updateITimeControl)
SearchHierarchyAndConnectControlableScripts(GetControlableScripts(sourceObject), graph, playables);
// Connect Playables to Generic to Mixer
root = ConnectPlayablesToMixer(graph, playables);
}
if (prefabGameObject != null)
s_CreatedPrefabs.Remove(prefabGameObject);
if (!root.IsValid())
root = Playable.Create(graph);
return root;
}
static Playable ConnectPlayablesToMixer(PlayableGraph graph, List<Playable> playables)
{
var mixer = Playable.Create(graph, playables.Count);
for (int i = 0; i != playables.Count; ++i)
{
ConnectMixerAndPlayable(graph, mixer, playables[i], i);
}
mixer.SetPropagateSetTime(true);
return mixer;
}
void CreateActivationPlayable(GameObject root, PlayableGraph graph,
List<Playable> outplayables)
{
var activation = ActivationControlPlayable.Create(graph, root, postPlayback);
if (activation.IsValid())
outplayables.Add(activation);
}
void SearchHierarchyAndConnectParticleSystem(IEnumerable<ParticleSystem> particleSystems, PlayableGraph graph,
List<Playable> outplayables)
{
foreach (var particleSystem in particleSystems)
{
if (particleSystem != null)
{
controllingParticles = true;
outplayables.Add(ParticleControlPlayable.Create(graph, particleSystem, particleRandomSeed));
}
}
}
void SearchHierarchyAndConnectDirector(IEnumerable<PlayableDirector> directors, PlayableGraph graph,
List<Playable> outplayables, bool disableSelfReferences)
{
foreach (var director in directors)
{
if (director != null)
{
if (director.playableAsset != m_ControlDirectorAsset)
{
outplayables.Add(DirectorControlPlayable.Create(graph, director));
controllingDirectors = true;
}
// if this self references, disable the director.
else if (disableSelfReferences)
{
director.enabled = false;
}
}
}
}
static void SearchHierarchyAndConnectControlableScripts(IEnumerable<MonoBehaviour> controlableScripts, PlayableGraph graph, List<Playable> outplayables)
{
foreach (var script in controlableScripts)
{
outplayables.Add(TimeControlPlayable.Create(graph, (ITimeControl)script));
}
}
static void ConnectMixerAndPlayable(PlayableGraph graph, Playable mixer, Playable playable,
int portIndex)
{
graph.Connect(playable, 0, mixer, portIndex);
mixer.SetInputWeight(playable, 1.0f);
}
internal IList<T> GetComponent<T>(GameObject gameObject)
{
var components = new List<T>();
if (gameObject != null)
{
if (searchHierarchy)
{
gameObject.GetComponentsInChildren<T>(true, components);
}
else
{
gameObject.GetComponents<T>(components);
}
}
return components;
}
internal static IEnumerable<MonoBehaviour> GetControlableScripts(GameObject root)
{
if (root == null)
yield break;
foreach (var script in root.GetComponentsInChildren<MonoBehaviour>())
{
if (script is ITimeControl)
yield return script;
}
}
internal void UpdateDurationAndLoopFlag(IList<PlayableDirector> directors, IList<ParticleSystem> particleSystems)
{
if (directors.Count == 0 && particleSystems.Count == 0)
return;
const double invalidDuration = double.NegativeInfinity;
var maxDuration = invalidDuration;
var supportsLoop = false;
foreach (var director in directors)
{
if (director.playableAsset != null)
{
var assetDuration = director.playableAsset.duration;
if (director.playableAsset is TimelineAsset && assetDuration > 0.0)
// Timeline assets report being one tick shorter than they actually are, unless they are empty
assetDuration = (double)((DiscreteTime)assetDuration).OneTickAfter();
maxDuration = Math.Max(maxDuration, assetDuration);
supportsLoop = supportsLoop || director.extrapolationMode == DirectorWrapMode.Loop;
}
}
foreach (var particleSystem in particleSystems)
{
maxDuration = Math.Max(maxDuration, particleSystem.main.duration);
supportsLoop = supportsLoop || particleSystem.main.loop;
}
m_Duration = double.IsNegativeInfinity(maxDuration) ? PlayableBinding.DefaultDuration : maxDuration;
m_SupportLoop = supportsLoop;
}
IList<ParticleSystem> GetControllableParticleSystems(GameObject go)
{
var roots = new List<ParticleSystem>();
// searchHierarchy will look for particle systems on child objects.
// once a particle system is found, all child particle systems are controlled with playables
// unless they are subemitters
if (searchHierarchy || go.GetComponent<ParticleSystem>() != null)
{
GetControllableParticleSystems(go.transform, roots, s_SubEmitterCollector);
s_SubEmitterCollector.Clear();
}
return roots;
}
static void GetControllableParticleSystems(Transform t, ICollection<ParticleSystem> roots, HashSet<ParticleSystem> subEmitters)
{
var ps = t.GetComponent<ParticleSystem>();
if (ps != null)
{
if (!subEmitters.Contains(ps))
{
roots.Add(ps);
CacheSubEmitters(ps, subEmitters);
}
}
for (int i = 0; i < t.childCount; ++i)
{
GetControllableParticleSystems(t.GetChild(i), roots, subEmitters);
}
}
static void CacheSubEmitters(ParticleSystem ps, HashSet<ParticleSystem> subEmitters)
{
if (ps == null)
return;
for (int i = 0; i < ps.subEmitters.subEmittersCount; i++)
{
subEmitters.Add(ps.subEmitters.GetSubEmitterSystem(i));
// don't call this recursively. subEmitters are only simulated one level deep.
}
}
/// <inheritdoc/>
public void GatherProperties(PlayableDirector director, IPropertyCollector driver)
{
// This method is no longer called by Control Tracks.
if (director == null)
return;
// prevent infinite recursion
if (s_ProcessedDirectors.Contains(director))
return;
s_ProcessedDirectors.Add(director);
var gameObject = sourceGameObject.Resolve(director);
if (gameObject != null)
{
if (updateParticle)// case 1076850 -- drive all emitters, not just roots.
PreviewParticles(driver, gameObject.GetComponentsInChildren<ParticleSystem>(true));
if (active)
PreviewActivation(driver, new[] { gameObject });
if (updateITimeControl)
PreviewTimeControl(driver, director, GetControlableScripts(gameObject));
if (updateDirector)
PreviewDirectors(driver, GetComponent<PlayableDirector>(gameObject));
}
s_ProcessedDirectors.Remove(director);
}
internal static void PreviewParticles(IPropertyCollector driver, IEnumerable<ParticleSystem> particles)
{
foreach (var ps in particles)
{
driver.AddFromName<ParticleSystem>(ps.gameObject, "randomSeed");
driver.AddFromName<ParticleSystem>(ps.gameObject, "autoRandomSeed");
}
}
internal static void PreviewActivation(IPropertyCollector driver, IEnumerable<GameObject> objects)
{
foreach (var gameObject in objects)
driver.AddFromName(gameObject, "m_IsActive");
}
internal static void PreviewTimeControl(IPropertyCollector driver, PlayableDirector director, IEnumerable<MonoBehaviour> scripts)
{
foreach (var script in scripts)
{
var propertyPreview = script as IPropertyPreview;
if (propertyPreview != null)
propertyPreview.GatherProperties(director, driver);
else
driver.AddFromComponent(script.gameObject, script);
}
}
internal static void PreviewDirectors(IPropertyCollector driver, IEnumerable<PlayableDirector> directors)
{
foreach (var childDirector in directors)
{
if (childDirector == null)
continue;
var timeline = childDirector.playableAsset as TimelineAsset;
if (timeline == null)
continue;
timeline.GatherProperties(childDirector, driver);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 48853ae485fa386428341ac1ea122570
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,70 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
namespace UnityEngine.Timeline
{
/// <summary>
/// A Track whose clips control time-related elements on a GameObject.
/// </summary>
[TrackClipType(typeof(ControlPlayableAsset), false)]
[ExcludeFromPreset]
[TimelineHelpURL(typeof(ControlTrack))]
public class ControlTrack : TrackAsset
{
#if UNITY_EDITOR
private static readonly HashSet<PlayableDirector> s_ProcessedDirectors = new HashSet<PlayableDirector>();
/// <inheritdoc/>
public override void GatherProperties(PlayableDirector director, IPropertyCollector driver)
{
if (director == null)
return;
// avoid recursion
if (s_ProcessedDirectors.Contains(director))
return;
s_ProcessedDirectors.Add(director);
var particlesToPreview = new HashSet<ParticleSystem>();
var activationToPreview = new HashSet<GameObject>();
var timeControlToPreview = new HashSet<MonoBehaviour>();
var subDirectorsToPreview = new HashSet<PlayableDirector>();
foreach (var clip in GetClips())
{
var controlPlayableAsset = clip.asset as ControlPlayableAsset;
if (controlPlayableAsset == null)
continue;
var gameObject = controlPlayableAsset.sourceGameObject.Resolve(director);
if (gameObject == null)
continue;
if (controlPlayableAsset.updateParticle)
particlesToPreview.UnionWith(gameObject.GetComponentsInChildren<ParticleSystem>(true));
if (controlPlayableAsset.active)
activationToPreview.Add(gameObject);
if (controlPlayableAsset.updateITimeControl)
timeControlToPreview.UnionWith(ControlPlayableAsset.GetControlableScripts(gameObject));
if (controlPlayableAsset.updateDirector)
subDirectorsToPreview.UnionWith(controlPlayableAsset.GetComponent<PlayableDirector>(gameObject));
}
ControlPlayableAsset.PreviewParticles(driver, particlesToPreview);
ControlPlayableAsset.PreviewActivation(driver, activationToPreview);
ControlPlayableAsset.PreviewTimeControl(driver, director, timeControlToPreview);
ControlPlayableAsset.PreviewDirectors(driver, subDirectorsToPreview);
s_ProcessedDirectors.Remove(director);
particlesToPreview.Clear();
activationToPreview.Clear();
timeControlToPreview.Clear();
subDirectorsToPreview.Clear();
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15e0374501f39d54eb30235764636e0e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More