Unity Timeline学习笔记(4) - 自定义轨道OnCreateClip和CreateTrackMixer用法上的区分

前面我们第二篇文章Unity Timeline学习笔记(2) - PlayableTrack是一个初步的PlayableTrack使用方法,有时候可能会个性化定制专属轨道。

OnCreateClip的例子

下面我们做一个例子:
首先是轨道
在这里插入图片描述

//FeatureTrack.cs
using System.ComponentModel;
using UnityEngine.Timeline;

[DisplayName("(Feature)开关轨道")]
[TrackClipType(typeof(FeaturePlayableAsset))]
[TrackColor(0.53f, 0.0f, 0.08f)]//表示在编辑器中,Track轨道前端的标识颜色(不重要啦)
public class FeatureTrack : TrackAsset
{
    protected override void OnCreateClip(TimelineClip clip)
    {
        base.OnCreateClip(clip);
        clip.displayName = "Clip显示名称";
    }
}

这里有TrackClipType表示我们只能添加类型为FeaturePlayableAsset的对象。

我们把PlayableAsset代码也放上:

//FeaturePlayableAsset.cs
using System;
using System.ComponentModel;
using UnityEngine;
using UnityEngine.Playables;

[DisplayName("(Feature)开关Clip")]
[Serializable]
public class FeaturePlayableAsset : PlayableAsset
{
    public string featureName;
    public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
    {
        var p = ScriptPlayable<FeaturePlayableBehaviour>.Create(graph);

        var b = p.GetBehaviour();
        b.featureName = featureName;

        return p;
    }
}

public class FeaturePlayableBehaviour : PlayableBehaviour
{
    public string featureName;
    // 当进入区域内触发Play
    public override void OnBehaviourPlay(Playable playable, FrameData info)
    {
        Debug.Log($"触发 OnBehaviourPlay ,name: {featureName}");
    }

    // 当出了区域触发,或者开始的时候触发,或者停止运行的时候
    public override void OnBehaviourPause(Playable playable, FrameData info)
    {
        Debug.Log($"触发 OnBehaviourPause , name: {featureName}");
    }

     在区域内每个Frame地方都会触发

    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        var p = (float)(playable.GetTime() / playable.GetDuration());
        //Debug.Log($"{featureName} - {p.ToString("F2")} , time:{playable.GetTime()} ,dur:{playable.GetDuration()}");
    }

}

我们这时候可以在轨道上点击鼠标右键,就只能看到只有这个对象了。
在这里插入图片描述
在这里插入图片描述
OnBehaviourPlay进入clip就触发。
OnBehaviourPause出了clip就触发。
当然Pause在运行时候会触发一次。

当前滑块可以用playable.GetTime() / playable.GetDuration()的方式获得到百分比。

这种就是OnCreateClip的用法。
下面我们来看CreateTrackMixer的用法

CreateTrackMixer的用法

因为目前我没有用到需要Mixer的算法,可能认识上有点偏差,我的理解是Mixer就是如图
在这里插入图片描述
交叉的这部分,如果某个值需要混合可以按照自己的需求去计算数值,权重可以这样获取:

float inputWeight = playable.GetInputWeight(i);

我们先放上代码,然后再做对比。

首先是轨道

//FeatureMixerTrack.cs
using System.ComponentModel;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

[DisplayName("(FeatureMixer)开关轨道")]
[TrackClipType(typeof(FeatureMixerPlayableAsset))]
[TrackColor(0.53f, 0.0f, 0.08f)]//表示在编辑器中,Track轨道前端的标识颜色(不重要啦)
public class FeatureMixerTrack : TrackAsset
{
    public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
    {
        var temp = ScriptPlayable<FeatureMixerPlayableBehaviour>.Create(graph, inputCount);
        temp.GetBehaviour().fixedData = "传入的数据";
        return temp;
    }
    
}

这里调用了CreateTrackMixer的方法。

//FeatureMixerPlayableAsset.cs
using System;
using System.ComponentModel;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

[DisplayName("(FeatureMixer)开关Clip")]
[Serializable]
public class FeatureMixerPlayableAsset : PlayableAsset
{
    public FeatureBehaviour template = new FeatureBehaviour();
    public ClipCaps clipCaps
    {
        get
        {
            return ClipCaps.Blending;
        }
    }
    public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
    {
        return ScriptPlayable<FeatureBehaviour>.Create(graph, template);
    }
}

[Serializable]
public class FeatureBehaviour : PlayableBehaviour
{
    public string featureName;  //开启某个feature
    public Material material;   //对应的材质球
    public AnimationCurve alphaCurve;   //修改某个参数

    [HideInInspector]
    public float passtime;  //计算当前块的播放进度
    [HideInInspector]
    public bool started;  //是否刚进入
}


public class FeatureMixerPlayableBehaviour : PlayableBehaviour
{
    public string fixedData;

    // 当进入区域内触发Play
    public override void OnBehaviourPlay(Playable playable, FrameData info)
    {
        Debug.Log("触发 OnBehaviourPlay");
    }

    // 当出了区域触发,或者开始的时候触发,或者停止运行的时候
    public override void OnBehaviourPause(Playable playable, FrameData info)
	{
	    int inputCount = playable.GetInputCount();
	    for (int i = 0; i < inputCount; i++)
	    {
	        ScriptPlayable<FeatureBehaviour> inputPlayable = (ScriptPlayable<FeatureBehaviour>)playable.GetInput(i);
	        FeatureBehaviour input = inputPlayable.GetBehaviour();
	        if (input.started)
	        {
	            input.started = false;
	            Debug.Log($"{input.featureName}出去了!!");
	        }
	    }
	}

    // 在区域内每个Frame地方都会触发

    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        int inputCount = playable.GetInputCount();
        for (int i = 0; i < inputCount; i++)
        {
            ScriptPlayable<FeatureBehaviour> inputPlayable = (ScriptPlayable<FeatureBehaviour>)playable.GetInput(i);
            FeatureBehaviour input = inputPlayable.GetBehaviour();

            float inputWeight = playable.GetInputWeight(i);

            if (!Mathf.Approximately(inputWeight, 0f))
            {
                input.passtime += info.deltaTime;

                // maxTime 当前clip的时长
                float maxTime = (float)PlayableExtensions.GetDuration(playable.GetInput(i));
                // curTime 当前clip的执行到哪个时刻
                float nowValue = input.alphaCurve.Evaluate(input.passtime / maxTime);
                //Debug.Log("" + input.featureName + "," + (input.passtime / maxTime) + ",nowValue:" + nowValue);

                //更新材质的变量
                //input.material.SetFloat("xxxx", nowValue);
                if (!input.started)
                {
                    input.started = true;
                    Debug.Log($"{input.featureName} 进入了");
                }
            }
            else
            {
                input.passtime = 0f;
                if (input.started)
                {
                    input.started = false;
                    Debug.Log($"{input.featureName} 出去了");
                }
            }
        }
    }

}

在这里插入图片描述

Mixer轨道在使用中发现和普通的轨道有区别:

函数OnBehaviourPlay和OnBehaviourPause失效

OnBehaviourPlay函数在TimeLine播放就执行了,并不会在clip进入才播放
OnBehaviourPause函数在整个TL播放结束才会进入。所以这两个函数失效了。

解决办法

我是这样解决的:
所以这里如果有进入和退出clip的时候要处理逻辑的,我研究可下加了两个变量来处理
started : 表示开始播放了
passtime :表示过去了多久

如果是Frame里的最后一帧刚好可能执行不到关闭,所以再OnBehaviourPause里也添加了结束.

具体就不描述了,参考代码中的ProcessFrame函数。

那么我们如果要处理每个clip,需要通过遍历来处理:

int inputCount = playable.GetInputCount();
for (int i = 0; i < inputCount; i++)

获取当前的有几个inputCount也是clip,然后遍历进行访问计算。

本文写道这里就结束,其实很多地方还没搞懂,例如ClipCaps设置为Blending后这个如何自定使用,后面有时间再研究吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/577563.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

以太网口硬件知识分享

一、了解网口通信基本原理 实现网络通信实质上是PHY与MAC及RJ45接口实现信号传输。MAC 就是以太网控制器&#xff0c;MAC属于数据链路层&#xff0c;主要负责把数据封装成帧&#xff0c;对帧进行界定实现帧同步。对MAC地址和源MAC地址及逆行相应的处理并对错误帧进行处理。PHY…

JavaScript-3(内置对象+数组对象+字符串对象)

目录 1.预解析 2.对象 什么是对象 创建对象的三种方法 利用字面量创建方法 利用new Object创建对象 构造函数创建对象 new关键字 遍历对象 3.内置对象 Math对象 Math概述 Math随机数 Date日期对象 格式化日期 Date总的时间毫秒 4.数组对象 创建数组的两种方式…

进销存单机版和excel进销存那个好用

进销存单机版和EXCEL进销存哪个好用&#xff1f;单机版是安装在单台电脑上使用的&#xff0c;它不能像网络版一样可以多台电脑同时共享数据&#xff0c;所以进销存单机版有一个优势就是不需要连接网络也可以使用。 进销存单机版 进销存软件单机版是经过开发人员设计好的一种信…

网页提示语闪太快的定位问题(selenium)

selenium UI自动化时&#xff0c;提示语闪太快&#xff0c;导致无法获取元素的问题 解决办法 步骤一&#xff1a; F12---》控制台输入debugger 步骤二&#xff1a;对于需要定位的部分&#xff0c;在控制台的debugger处回车&#xff0c;可以定住页面 步骤三&#xff1a;正常定…

生成式AI原理技术详解(一)——神经网络与深度学习

本文主要介绍了生成式AI的最新发展&#xff0c;提到了GPT-5和AI软件工程师在行业中的影响&#xff0c;指出AI技术进步对国家竞争和个人职业发展的潜在影响。 未来已来 最近有两则新闻&#xff1a; sam altman自曝GPT-5细节&#xff0c;公开宣称GPT-5提升将非常大&#xff0c;任…

62、回溯-N皇后

思路&#xff1a; N皇后问题要求在一个nn的棋盘上放置n个皇后&#xff0c;使得它们不能相互攻击。皇后可以攻击同一行、同一列&#xff0c;以及两个对角线方向上的其他皇后。解决这个问题意味着找到所有可能的棋盘配置&#xff0c;每个配置都符合上述条件。 1、初始化数据结构…

Docker 入门篇(二)-- Linux 环境离线安装

引言 docker 系列文章&#xff1a; Docker 入门篇&#xff08;一&#xff09;-- 简介与安装教程&#xff08;Windows和Linux&#xff09; 一、安装环境准备 centos &#xff1a;CentOS Linux release 7.6.1810 (Core)docker 版本&#xff1a;docker-26.1.0.tgz 官网下载地址…

Linux驱动开发——(七)Linux阻塞和非阻塞IO

目录 一、阻塞和非阻塞IO简介 二、等待队列 2.1 等待队列头 2.2 等待队列项 2.3 将队列项添加/移除等待队列头 2.4 等待唤醒 2.5 等待事件 三、轮询 四、驱动代码 4.1 阻塞IO 4.2 非阻塞IO 一、阻塞和非阻塞IO简介 IO指的是Input/Output&#xff0c;也就是输入/输…

十个案例学习Flume

在上一篇文章中&#xff0c;已经知道了Flume的架构、概述、与安装&#xff0c;现在我们来用十个案例去学习flume的使用。 在使用之前&#xff0c;提供一个大致思想&#xff0c;使用Flume的过程是确定scource类型&#xff0c;channel类型和sink类型&#xff0c;编写conf文件并开…

零基础HTML教程(30)--迈入HTML5新时代

文章目录 1. 从H4时代到H5时代2. 属性值可以不用引号3. 标签使用大小写均可4. 部分属性值可以省略5. 浏览器支持情况6. 小结 1. 从H4时代到H5时代 之前讲的29篇HTML教程&#xff0c;内容基本都是H4时代就有的。 随着时代的发展&#xff0c;H4多少有点不够用&#xff0c;所以H…

Kotlin基础​​

数据类型 定义变量 var表示定义变量&#xff0c;可以自动推导变量类型&#xff0c;所以Int可以不用写。 定义常量 条件语句 if表达式可以返回值&#xff0c;该值一般写在if里的最后一行 类似switch的用法 区间 循环 a是标签&#xff0c;可以直接break到标签的位置&#xf…

【八大排序(二)】选择排序与堆排序

❣博主主页: 33的博客❣ ▶️文章专栏分类:八大排序◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多排序知识 目录 1.前言2.选择排序2.1基本思想2.2画图理解2.3单向选择排序代码实现2.4双向选择排序代码…

从零入门区块链和比特币(第一期)

欢迎来到我的区块链与比特币入门指南&#xff01;如果你对区块链和比特币感兴趣&#xff0c;但不知道从何开始&#xff0c;那么你来对地方了。本博客将为你提供一个简明扼要的介绍&#xff0c;帮助你了解这个领域的基础知识&#xff0c;并引导你进一步探索这个激动人心的领域。…

swagger xss漏洞复现

swagger xss漏洞复现 文章目录 swagger xss漏洞复现漏洞介绍影响版本实现原理漏洞复现修复建议: 漏洞介绍 Swagger UI 有一个有趣的功能&#xff0c;允许您提供 API 规范的 URL - 一个 yaml 或 json 文件&#xff0c;将被获取并显示给用户 根本原因非常简单 - 一个过时的库Dom…

预见预判|AIRIOT智慧交通管理解决方案

随着机动车保有量的逐步增加&#xff0c;城市交通压力日益增大。同时&#xff0c;新能源车辆的快速发展虽然带来了环保效益&#xff0c;但也因不限号政策而进一步加剧了道路拥堵问题。此外&#xff0c;各类赛事和重大活动的交通管制措施也时常导致交通状况复杂多变。面对这些挑…

Java 基础常见面试题整理

目录 1、java的基本数据类型有哪些&#xff1f;2、java为什么要有包装类型&#xff1f;3、String a "123" 和 String a new String("123") 区别&#xff1f;4、String、StringBuilder和StringBuffer的区别&#xff1f;5、如何理解面向对象和面向过程&…

MySQL常见问题与解决方案详述

MySQL&#xff1a;常见问题与解决方案详述 作为一款广泛使用的开源关系型数据库管理系统&#xff0c;MySQL对于初学者来说既充满吸引力又充满挑战。本文将列举初学者在使用MySQL过程中可能遇到的一些典型问题&#xff0c;并提供详细的解决方案&#xff0c;配以图片辅助说明&am…

修改后门ctime | Linux 后门系列

0x00 前情提要 在 alias 后门 &#xff5c; Linux 后门系列一文中&#xff0c;我们为了让后门完美一些&#xff0c;修改了后门文件的 atime、mtime&#xff0c;但是 ctime 一直没有办法修改&#xff0c;今天我们来把这一块补齐&#xff0c;让后门更加完美 atime -> access t…

Chrome 网络调试程序 谷歌网络调试 network

目录 1.网络面板总览2.概况了解3.Waterfall接口排队等待时间4.关注请求接口的Size,可能是占据内存溢出的接口5.过滤器一栏 fetch/xhr 什么意思6. Stalled 什么意思7.Queueing 什么意思8.Queueing和Stalled之间什么关系9.为什么会有阻塞状态10.Time列是pending 什么意思 1.网络面…

Vue入门篇:生命周期,钩子函数,工程化开发Vue(脚手架安装),组件化开发(全局注册,局部注册)

目录 1.Vue生命周期和生命周期的四个阶段2.Vue生命周期函数&#xff08;钩子函数)3.工程化开发&脚手架Vue CLI1.在powershell管理员权限下打开命令行安装脚手架&#xff1a;2.查看vue版本&#xff1a;3.创建项目架子4.运行项目 4.组件化开发&根组件1.App.vue文件&#…