Source code analysis of Unity Timeline custom track DefaultPlayables

DefaultPlayables source code

DefaultPlayables provides seven additional tracks with the support of Unity's native tracks.

  • LightControl
  • NavMeshAgentControl
  • ScreenFader
  • Video
  • TransformTween
  • TimeDilation
  • TextSwitcher

Taking LightControl as an example, we mainly have the following four scripts:

LightControlBehaviour,LightControlClip,LightControlMixerBehaviour,LightControlTrack

The drawing under Editor has a script:

LightControlDrawer

Combined with my previous articles:

Unity Timeline custom track_ Endless blog - CSDN blog

Tracks on the Timeline are managed by LightControlTrack.

When mixing, LightControlMixerBehaviour is created, and the basic information of the light attribute of the bound object is obtained under the Editor.

[TrackColor(0.9454092f, 0.9779412f, 0.3883002f)]
[TrackClipType(typeof(LightControlClip))]
[TrackBindingType(typeof(Light))]
public class LightControlTrack : TrackAsset
{
    public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
    {
        return ScriptPlayable<LightControlMixerBehaviour>.Create (graph, inputCount);
    }

    public override void GatherProperties(PlayableDirector director, IPropertyCollector driver)
    {
#if UNITY_EDITOR
       Light trackBinding = director.GetGenericBinding(this) as Light;
       if (trackBinding == null)
           return;
       driver.AddFromName<Light>(trackBinding.gameObject, "m_Color");
       driver.AddFromName<Light>(trackBinding.gameObject, "m_Intensity");
       driver.AddFromName<Light>(trackBinding.gameObject, "m_Range");
       driver.AddFromName<Light>(trackBinding.gameObject, "m_BounceIntensity");
#endif
        base.GatherProperties(director, driver);
    }
}

LightControlMixerBehaviour controls the specific behavior. You can see that it first records the default light attributes at the first frame, and then through playable Getinput series methods obtain each Input of the Input, mix and calculate by their weight, and then assign the result to the bound object Light m_TrackBinding.

Finally, restore its basic light attributes in OnPlayableDestroy.

public class LightControlMixerBehaviour : PlayableBehaviour
{
    Color m_DefaultColor;
    float m_DefaultIntensity;
    float m_DefaultBounceIntensity;
    float m_DefaultRange;

    Light m_TrackBinding;
    bool m_FirstFrameHappened;

    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        m_TrackBinding = playerData as Light;

        if (m_TrackBinding == null)
            return;

        if (!m_FirstFrameHappened)
        {
            m_DefaultColor = m_TrackBinding.color;
            m_DefaultIntensity = m_TrackBinding.intensity;
            m_DefaultBounceIntensity = m_TrackBinding.bounceIntensity;
            m_DefaultRange = m_TrackBinding.range;
            m_FirstFrameHappened = true;
        }

        int inputCount = playable.GetInputCount ();

        Color blendedColor = Color.clear;
        float blendedIntensity = 0f;
        float blendedBounceIntensity = 0f;
        float blendedRange = 0f;
        float totalWeight = 0f;
        float greatestWeight = 0f;
        int currentInputs = 0;

        for (int i = 0; i < inputCount; i++)
        {
            float inputWeight = playable.GetInputWeight(i);
            ScriptPlayable<LightControlBehaviour> inputPlayable = (ScriptPlayable<LightControlBehaviour>)playable.GetInput(i);
            LightControlBehaviour input = inputPlayable.GetBehaviour ();
            
            blendedColor += input.color * inputWeight;
            blendedIntensity += input.intensity * inputWeight;
            blendedBounceIntensity += input.bounceIntensity * inputWeight;
            blendedRange += input.range * inputWeight;
            totalWeight += inputWeight;

            if (inputWeight > greatestWeight)
            {
                greatestWeight = inputWeight;
            }

            if (!Mathf.Approximately (inputWeight, 0f))
                currentInputs++;
        }

        m_TrackBinding.color = blendedColor + m_DefaultColor * (1f - totalWeight);
        m_TrackBinding.intensity = blendedIntensity + m_DefaultIntensity * (1f - totalWeight);
        m_TrackBinding.bounceIntensity = blendedBounceIntensity + m_DefaultBounceIntensity * (1f - totalWeight);
        m_TrackBinding.range = blendedRange + m_DefaultRange * (1f - totalWeight);
    }

    public override void OnPlayableDestroy (Playable playable)
    {
        m_FirstFrameHappened = false;

        if(m_TrackBinding == null)
            return;

        m_TrackBinding.color = m_DefaultColor;
        m_TrackBinding.intensity = m_DefaultIntensity;
        m_TrackBinding.bounceIntensity = m_DefaultBounceIntensity;
        m_TrackBinding.range = m_DefaultRange;
    }
}

LightControlClip and lightcontrolbehavior data sources. Complete the responsibility of passing the template data to the past in the CreatePlayable method of LightControlClip.

[Serializable]
public class LightControlClip : PlayableAsset, ITimelineClipAsset
{
    public LightControlBehaviour template = new LightControlBehaviour ();

    public ClipCaps clipCaps
    {
        get { return ClipCaps.Blending; }
    }

    public override Playable CreatePlayable (PlayableGraph graph, GameObject owner)
    {
        var playable = ScriptPlayable<LightControlBehaviour>.Create (graph, template);
        return playable;    }
}
[Serializable]
public class LightControlBehaviour : PlayableBehaviour
{
    public Color color = Color.white;
    public float intensity = 1f;
    public float bounceIntensity = 1f;
    public float range = 10f;
}

LightControlDrawer is responsible for custom drawing of the inspector under Editor.

[CustomPropertyDrawer(typeof(LightControlBehaviour))]
public class LightControlDrawer : PropertyDrawer
{
    public override float GetPropertyHeight (SerializedProperty property, GUIContent label)
    {
        int fieldCount = 4;
        return fieldCount * EditorGUIUtility.singleLineHeight;
    }

    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
    {
        SerializedProperty colorProp = property.FindPropertyRelative("color");
        SerializedProperty intensityProp = property.FindPropertyRelative("intensity");
        SerializedProperty bounceIntensityProp = property.FindPropertyRelative("bounceIntensity");
        SerializedProperty rangeProp = property.FindPropertyRelative("range");

        Rect singleFieldRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
        EditorGUI.PropertyField(singleFieldRect, colorProp);
        
        singleFieldRect.y += EditorGUIUtility.singleLineHeight;
        EditorGUI.PropertyField(singleFieldRect, intensityProp);
        
        singleFieldRect.y += EditorGUIUtility.singleLineHeight;
        EditorGUI.PropertyField(singleFieldRect, bounceIntensityProp);
        
        singleFieldRect.y += EditorGUIUtility.singleLineHeight;
        EditorGUI.PropertyField(singleFieldRect, rangeProp);
    }
}

The other six track structures are similar to this, and they are not expanded one by one.

Default Playables helper

See this article for more details:

Unity - Timeline custom clip, track, blend track, Inspector attribute display (using the Default Playables helper)_ Jave.Lin's study notes - CSDN blog

Opens the wizard panel of the accessibility tool.

Playable Name

The first is our clip name. For example: TestScale.

Then the tool will help us automatically create the following classes:

Xxxxbehaviour: playablebehavior - the content to be processed by ordinary editing logic. The logic can also be written to mixed editing logic.
Xxxxclip: playableasset, itimelineclipasset - the data content to be saved by the clip asset.
Xxxxmixerbehaviour: playablebehavior - the content to be processed by the mixed editing logic, the collection or processing of mixed data, in fact, you can only collect data here, and then transfer it to the ordinary editing logic to process mixing.
Xxxxtrack: trackasset - the content to be processed by the track resource, which mainly allows the track to use which logical classes to handle mixing when processing mixing.
Xxxxdrawer: propertydraw - Clip property plotter, which mainly processes the clip selected in the Clips view of Timeline and the drawing content displayed in the Inspector window.

Standard Blend Playable

Whether to create a standard mixable Playable.
The difference is:

When selected, Track Binding Type can be selected: it can be instantiated and inherited from unityengine All classes of component.
If not selected, Track Binding Type can be selected: inherited from unityengine In addition to all classes of component, you can also select GameObject and null.

Track Binding Type

This is the type of data object that Track receives and processes.


Exposed References

Because the variables in Timeline cannot directly expose the applied type variables.
Therefore, it is a special independent item to add variables of reference type to separate them from those of value type.
If Standard Blend Playable is selected, Exposed References is not displayed, that is, no settings are provided.
Click the 'Add' button and a new variable column will appear. Then you can rename the default name of the variable: newBehaviourVariable to what you want. There is also the type selection of the variable on the right.
Click the 'Remove' button to delete the corresponding variable.


Behaviour Variables

Variables of behavioral logic class.

If Standard Blend Playable is selected, it will be called: Standard Blend Playable Properties. The names are inconsistent.
Click the 'Add' button and a new variable column will appear. Then you can rename the default name of the variable: newBehaviourVariable to what you want. There is also the type selection of the variable on the right.
Click the 'Remove' button to delete the corresponding variable.


Clip Caps

Can be understood as: clip's built-in function start option.

If the function is enabled, some common attribute items of the clip will be displayed in the Inspector.

It is defined in the script as follows:

public enum ClipCaps
{
	All = -1,
	None = 0,
	Looping = 1,
	Extrapolation = 2,
	ClipIn = 4,
	SpeedMultiplier = 8,
	Blending = 16
}

Introduction to ClipCaps enumeration

  • All is to start all built-in editing functions.
  • None is enabled. Only the start, end and duration of the Clip Timing attribute can be adjusted.
  • Looping can loop the in the clip as long as the clip is still playing.
  • The Extrapolation is enabled, and the settings of Clip Extrapolation for editing clip are displayed. You can extrapolate simulation data for blank content.
  • Clip In is turned on and clip clipping settings are provided. Animation Clip is generally useful.
  • Speedmultipler is turned on to speed up the playback of the contents of the clip. Generally, Animation Clip is useful.
  • When Blending is enabled, you can mix and transition blank content and clip content.

Track Color

The color of the track.

Create Drawer

Whether to create the Inspector attribute painter for the clip.

Keywords: Unity timeline

Added by phynias on Sat, 11 Dec 2021 04:07:04 +0200