当前位置:   article > 正文

Unity - Timeline 自定义剪辑,轨道,混合轨道,Inspector属性显示(使用Default Playables辅助工具)_timelinescrollinner bs剪辑

timelinescrollinner bs剪辑

Timeline中,可以通过脚本扩展自定义的剪辑,轨道,混合轨道,Inspector属性显示器。

我这里参考了官方的 Default Playables的一个节点扩展方式,它也提供了一个辅助工具,非常方便,基本上我们只管处理轨道、混合轨道处理的逻辑就好了,其他的只需要鼠标点点点就可以创建好你想要的效果。

当然,如果辅助工具某些功能不满足你想要的,你也可以自己编辑脚本来扩展。

那下面我们就用这个辅助工具来创建自定义内容吧。

工具面板

首先打开辅助工具的向导面板
在这里插入图片描述

Playable Name

首先是我们的剪辑名字

如:TestingTRS_Scale
在这里插入图片描述

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

  • 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,的额外两种。

从代码中可以看出来:

        if (isStandardBlendPlayable) // 选中 Standard Blend Playable
        {
            oldIndex = m_ComponentBindingTypeIndex;

            m_ComponentBindingTypeIndex = EditorGUILayout.Popup (m_TrackBindingTypeContent, m_ComponentBindingTypeIndex, UsableType.GetGUIContentWithSortingArray (s_ComponentTypes)); // 使用的是集合:s_ComponentTypes
            trackBinding = s_ComponentTypes[m_ComponentBindingTypeIndex];

            EditorGUILayout.Space ();

            defaultValuesComponent = EditorGUILayout.ObjectField (m_DefaultValuesComponentContent, defaultValuesComponent, trackBinding.type, true) as Component;
        }
        else // 没选
        {
            m_TrackBindingTypeIndex = EditorGUILayout.Popup(m_TrackBindingTypeContent, m_TrackBindingTypeIndex, UsableType.GetGUIContentWithSortingArray(s_TrackBindingTypes)); // 使用的是集合:s_TrackBindingTypes
            trackBinding = s_TrackBindingTypes[m_TrackBindingTypeIndex];
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

可以看到分别使用了不一样的TrackBindingType的集合而已,那再去看看这两个集合的收集区别

        Type[] componentTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => typeof(Component).IsAssignableFrom(t)).Where (t => t.IsPublic).ToArray();
        
        List<UsableType> componentUsableTypesList = UsableType.GetUsableTypeArray(componentTypes).ToList();
        componentUsableTypesList.Sort();
        s_ComponentTypes = componentUsableTypesList.ToArray (); // Starndard Blend Playable == true是使用的TrackBindingType的集合

        UsableType gameObjectUsableType = new UsableType(typeof(GameObject));
        UsableType[] defaultUsableTypes = UsableType.GetUsableTypeArray(componentTypes, gameObjectUsableType);

        List<UsableType> exposedRefTypeList = defaultUsableTypes.ToList ();
        exposedRefTypeList.Sort();
        s_ExposedReferenceTypes = exposedRefTypeList.ToArray();

        UsableType noneType = new UsableType((Type)null);
        s_TrackBindingTypes = UsableType.AmalgamateUsableTypes(s_ExposedReferenceTypes, noneType); // Starndard Blend Playable == false是使用的TrackBindingType的集合
        // 所以我们可以看到,仅仅比s_ComponentTypes ,多了个:GameObject,与null类。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

选中前的界面

当你选中了 Standard Blend Playable后,你会发现界面精简了很多。
在这里插入图片描述

选中后的界面

在这里插入图片描述

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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

ClipCaps的枚举简介

  • All 就是开始所有内置的剪辑功能。
  • None 啥都不开启,只有 Clip Timing属性的Start,End,Duration可调整
  • Looping 描述说的是,可以对剪辑内的可以循环播放,只要剪辑还处于播放中的话(目前这个没看到有什么用)
  • Extrapolation 开启,并显示对剪辑编辑Clip Extrapolation的设置,可以对空白内容的外插模拟数据
  • Clip In 开启,并提供可对剪辑的裁剪设置,一般Animation Clip才有用。自定义脚本我决定没啥用。
  • SpeedMultiplier 开启,对剪辑的内容加速播放。一般Animation Clip才有用。
  • Blending 开启后,可以对空白内容与剪辑内容的混合过渡处理。

Track Color

轨道的颜色

在这里插入图片描述

如果调整为红色,那么Timeline中的轨道左侧红色条,与剪辑下面的红色条,就是Track Color。
在这里插入图片描述

Create Drawer?

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

如下图的红色框中的,就是选中 Create Drawer后的结果。

在这里插入图片描述

选中 Create Drawer,对应编辑器代码:

using UnityEditor;
using UnityEngine;

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

    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
    {
        SerializedProperty scaleXProp = property.FindPropertyRelative("scaleX");
        SerializedProperty scaleYProp = property.FindPropertyRelative("scaleY");
        SerializedProperty scaleZProp = property.FindPropertyRelative("scaleZ");

        Rect singleFieldRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
        EditorGUI.PropertyField(singleFieldRect, scaleXProp);

        singleFieldRect.y += EditorGUIUtility.singleLineHeight;
        EditorGUI.PropertyField(singleFieldRect, scaleYProp);

        singleFieldRect.y += EditorGUIUtility.singleLineHeight;
        EditorGUI.PropertyField(singleFieldRect, scaleZProp);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

没选 Create Drawer,对应编辑器代码:

using UnityEditor;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.UI;

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

    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
    {

        Rect singleFieldRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

面板里的基本介绍得差不多了

下面说说,主要扩展混合剪辑的代码
介绍说明我都写注释里吧

主要看:// === add start ===// === add end ===之间的内容,其他都是生成的代码。

using System;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

public class TestingTRS_ScaleMixerBehaviour : PlayableBehaviour
{
    // === add start ===
    // 一些辅助变量
    private bool firstFrae = false;             // 是否处理过第一帧的逻辑
    private Vector3 srcScale = Vector3.one;     // 轨道处理前的原始缩放值
    private Transform trackBinding;             // 这个就是我嗯Track Binding Type指定的类型变量
    // === add end ===

    // NOTE: This function is called at runtime and edit time.  Keep that in mind when setting the values of properties.
    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        trackBinding = playerData as Transform;

        if (!trackBinding)
            return;

        // === add start ===
        if (!firstFrae) // 没有处理过第一帧
        {
            firstFrae = true; // 处理过了,将标识打上
            srcScale = trackBinding.localScale; // 记录轨道处理前的数据
        }
        // === add end ===

        int inputCount = playable.GetInputCount ();

        // === add start ===
        float totalWeight = 0;          // 总的混合权重
        float blendX = 0;               // scaleX的混合值
        float blendY = 0;               // scaleY的混合值
        float blendZ = 0;               // scaleZ的混合值
        // === add end ===

        for (int i = 0; i < inputCount; i++)
        {
            float inputWeight = playable.GetInputWeight(i);
            ScriptPlayable<TestingTRS_ScaleBehaviour> inputPlayable = (ScriptPlayable<TestingTRS_ScaleBehaviour>)playable.GetInput(i);
            TestingTRS_ScaleBehaviour input = inputPlayable.GetBehaviour ();
            // Use the above variables to process each frame of this playable.
            // === add start ===
            totalWeight += inputWeight;                 // 累加混合权重
            blendX += inputWeight * input.scaleX;       // 根据权重值,将每一个剪辑的值都以混合权重值来做插值
            blendY += inputWeight * input.scaleY;
            blendZ += inputWeight * input.scaleZ;
            // === add end ===
        }

        // === add start ===
        trackBinding.localScale = new Vector3(blendX, blendY, blendZ);  // 将混合后的权重设置到binding数据中
        // === add end ===
    }
    // === add start ===
    public override void OnPlayableDestroy(Playable playable)           // 在剪辑销毁时恢复之前的缩放值
    {
        if (trackBinding != null && firstFrae)
        {
            firstFrae = false;
            trackBinding.localScale = srcScale;
        }
    }
    // === add end ===
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

创建Timeline,并运行效果

创建Timeline

选中TestTL对象,点击Timeline窗口中的Create按钮
在这里插入图片描述

添加轨道

  • 先删除不必要的默认添加的:Animation轨道
  • 再添加我们刚刚新创建的TestingTRS_Scale轨道
    在这里插入图片描述

设置Track Binding Data

  • 设置轨道Binding的数据对象
    因为我们的TestTRS_Scale接受的是Transform对象,Cube上有,我们就将它拖拽到轨道绑定的数据对象上吧。
    在这里插入图片描述

添加TestTRS_Scale剪辑,并设置剪辑数据

  • 我们添加了剪辑
  • 并对剪辑存储的数scaleX,scaleY,scaleZ都设置为2
  • 并对剪辑的名字设置为:2,2,2就是代表scaleX,Y,Z都是2,方便Timeline上的剪辑维护

在这里插入图片描述

复制多几个剪辑,再调整数据

  • Ctrl+D,或是Ctrl+C,V,来复制剪辑
  • 调整剪辑的scaleX数据
  • 调整剪辑的显示名字,方便维护
    在这里插入图片描述

先看看运行效果,很生硬的设置缩放值,后面添加混合会平滑很多
在这里插入图片描述

处理混合剪辑

  • 手动调整Clip Timing中的 Ease In DurationEase Out Duration分别可以调整剪辑对空白内容的插值过渡
  • 在Clip Edit Mode为Mix时,调整剪辑之间的位置,让他们有重叠位置,就可以混合了(当然脚本首先要支持MixerBehaviour)

混合的说明我之前翻译过一篇官方手册教程,可以看看:Unity - Timeline 之 Blending clips(混合剪辑)
在这里插入图片描述

再运行看看混合效果
在这里插入图片描述

Code

TestingTRS_ScaleBehaviour.cs

using System;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

[Serializable]
public class TestingTRS_ScaleBehaviour : PlayableBehaviour
{
    public float scaleX;
    public float scaleY;
    public float scaleZ;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

TestingTRS_ScaleClip.cs

using System;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

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

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

    public override Playable CreatePlayable (PlayableGraph graph, GameObject owner)
    {
        return ScriptPlayable<TestingTRS_ScaleBehaviour>.Create (graph, template);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

TestingTRS_ScaleMixerBehaviour.cs

using System;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

public class TestingTRS_ScaleMixerBehaviour : PlayableBehaviour
{
    // === add start ===
    // 一些辅助变量
    private bool firstFrae = false;             // 是否处理过第一帧的逻辑
    private Vector3 srcScale = Vector3.one;     // 轨道处理前的原始缩放值
    private Transform trackBinding;             // 这个就是我嗯Track Binding Type指定的类型变量
    // === add end ===

    // NOTE: This function is called at runtime and edit time.  Keep that in mind when setting the values of properties.
    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        trackBinding = playerData as Transform;

        if (!trackBinding)
            return;

        // === add start ===
        if (!firstFrae) // 没有处理过第一帧
        {
            firstFrae = true; // 处理过了,将标识打上
            srcScale = trackBinding.localScale; // 记录轨道处理前的数据
        }
        // === add end ===

        int inputCount = playable.GetInputCount ();

        // === add start ===
        float totalWeight = 0;          // 总的混合权重
        float blendX = 0;               // scaleX的混合值
        float blendY = 0;               // scaleY的混合值
        float blendZ = 0;               // scaleZ的混合值
        // === add end ===

        for (int i = 0; i < inputCount; i++)
        {
            float inputWeight = playable.GetInputWeight(i);
            ScriptPlayable<TestingTRS_ScaleBehaviour> inputPlayable = (ScriptPlayable<TestingTRS_ScaleBehaviour>)playable.GetInput(i);
            TestingTRS_ScaleBehaviour input = inputPlayable.GetBehaviour ();
            // Use the above variables to process each frame of this playable.
            // === add start ===
            totalWeight += inputWeight;                 // 累加混合权重
            blendX += inputWeight * input.scaleX;       // 根据权重值,将每一个剪辑的值都以混合权重值来做插值
            blendY += inputWeight * input.scaleY;
            blendZ += inputWeight * input.scaleZ;
            // === add end ===
        }

        // === add start ===
        trackBinding.localScale = new Vector3(blendX, blendY, blendZ);  // 将混合后的权重设置到binding数据中
        // === add end ===
    }
    // === add start ===
    public override void OnPlayableDestroy(Playable playable)           // 在剪辑销毁时恢复之前的缩放值
    {
        if (trackBinding != null && firstFrae)
        {
            firstFrae = false;
            trackBinding.localScale = srcScale;
        }
    }
    // === add end ===
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

TestingTRS_ScaleTrack.cs

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

[TrackColor(1f, 0f, 0.2057924f)]
[TrackClipType(typeof(TestingTRS_ScaleClip))]
[TrackBindingType(typeof(Transform))]
public class TestingTRS_ScaleTrack : TrackAsset
{
    public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
    {
        return ScriptPlayable<TestingTRS_ScaleMixerBehaviour>.Create (graph, inputCount);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

TestingTRS_ScaleDrawer.cs(Editor文件夹下)

using UnityEditor;
using UnityEngine;

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

    public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
    {
        SerializedProperty scaleXProp = property.FindPropertyRelative("scaleX");
        SerializedProperty scaleYProp = property.FindPropertyRelative("scaleY");
        SerializedProperty scaleZProp = property.FindPropertyRelative("scaleZ");

        Rect singleFieldRect = new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight);
        EditorGUI.PropertyField(singleFieldRect, scaleXProp);

        singleFieldRect.y += EditorGUIUtility.singleLineHeight;
        EditorGUI.PropertyField(singleFieldRect, scaleYProp);

        singleFieldRect.y += EditorGUIUtility.singleLineHeight;
        EditorGUI.PropertyField(singleFieldRect, scaleZProp);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

References

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/95479?site
推荐阅读
相关标签
  

闽ICP备14008679号