Unity Timeline自定义轨道 DefaultPlayables源码剖析

DefaultPlayables源码

DefaultPlayables在Unity原生的轨道支持下额外提供了7种轨道。

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

我们以LightControl为例,主要有以下4个脚本:

LightControlBehaviour、LightControlClip、LightControlMixerBehaviour、LightControlTrack

Editor下的绘制有一个脚本:

LightControlDrawer

结合我之前的文章:

Unity Timeline自定义轨道_漫漫无期的博客-CSDN博客

Timeline上的轨道由LightControlTrack进行管理。

在进行混合时创建出LightControlMixerBehaviour,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 完成具体行为上的控制,可以看到,它首先在第一帧时记录下默认的灯光属性,然后通过playable.GetInput系列方法获取输入的各个Input并由他们的权重进行混合计算,得出结果后再赋值给绑定的物体Light m_TrackBinding。

最后在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、LightControlBehaviour 数据来源。在LightControlClip的CreatePlayable方法中完成将template数据传递过去的责任。

[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负责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);
    }
}

其他6种轨道结构也与此类似,不一一展开。

Default Playables辅助工具

可以看下这篇文章更详细的介绍:

Unity - Timeline 自定义剪辑,轨道,混合轨道,Inspector属性显示(使用Default Playables辅助工具)_Jave.Lin 的学习笔记-CSDN博客

打开辅助工具的向导面板。
Unity Timeline自定义轨道 DefaultPlayables源码剖析

Playable Name

首先是我们的剪辑名字。如:TestScale。

那么工具会帮助我们自动创建以下几个类:

XXXXBehaviour : PlayableBehaviour - 普通剪辑逻辑要处理的内容,逻辑也可以写到混合剪辑逻辑。
XXXXClip : PlayableAsset, ITimelineClipAsset - 剪辑资源要保存的数据内容。
XXXXMixerBehaviour : PlayableBehaviour - 混合剪辑逻辑要处理的内容,对混合数据的收集,或是处理,其实也可以只在这里收集数据,然后传到 普通剪辑逻辑 里处理混合也是可以的。
XXXXTrack : TrackAsset - 轨道资源要处理的内容,主要让轨道在处理混合时,应该用哪些逻辑类来处理混合。
XXXXDrawer : PropertyDraw - 剪辑属性绘制器,主要处理在Timeline 的 Clips view中选中的剪辑,然后在Inspector窗口中显示的绘制内容。

Standard Blend Playable

是否创建标准的可混合的Playable。
选没选中,区别在于:

选中,Track Binding Type 可以选择: 可实例化,并继承自 UnityEngine.Component 的所有类。
没选,Track Binding Type 可以选择:继承自 UnityEngine.Component 的所有类外,还可以选中GameObject,与null,的额外两种。

Track Binding Type

就是Track接受处理的数据对象是什么类型的。


Exposed References

因为Timeline中的变量不能直接暴露应用的类型变量。
所以专门独立出来一项,添加引用类型的变量,以与值类型的分开。
如果Standard Blend Playable选中的话,Exposed References不显示,就是不提供设置。
点击’Add按钮’,出现新的一个变量栏,然后你可以对变量默认的名字:newBehaviourVariable,重命名成你想要的,右边还有变量的类型选择。
点击’Remove按钮’,可删除对应的变量。


Behaviour Variables

行为逻辑类的变量。

如果Standard Blend Playable选中的话,就叫:Standard Blend Playable Properties,叫法不一致而已。
点击’Add按钮’,出现新的一个变量栏,然后你可以对变量默认的名字:newBehaviourVariable,重命名成你想要的,右边还有变量的类型选择。
点击’Remove按钮’,可删除对应的变量。


Clip Caps

可理解为:剪辑的内置功能开始选项。

开启的功能,在Inspector中会显示一些该剪辑通用的属性项。

再脚本中定义如下:

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

ClipCaps的枚举简介

  • All 就是开始所有内置的剪辑功能。
  • None 啥都不开启,只有 Clip Timing属性的Start,End,Duration可调整。
  • Looping 可以对剪辑内的可以循环播放,只要剪辑还处于播放中的话。
  • Extrapolation 开启,并显示对剪辑编辑Clip Extrapolation的设置,可以对空白内容的外插模拟数据。
  • Clip In 开启,并提供可对剪辑的裁剪设置,一般Animation Clip才有用。
  • SpeedMultiplier 开启,对剪辑的内容加速播放。一般Animation Clip才有用。
  • Blending 开启后,可以对空白内容与剪辑内容的混合过渡处理。

Track Color

轨道的颜色。

Create Drawer

是否创建剪辑的Inspector属性绘制器。

上一篇:java.sql.SQLException:ResultSet关闭MySQL Java后不允许操作


下一篇:Android应用启动画面