Unity Timeline 扩展

news2025/3/14 6:31:05

这里认为大家已经会timeline的基本使用了,只介绍怎么自定义扩展。

第一步.自定义Track

首先要自定义一条轨道。剪辑是要在轨道里跑的,系统自带的轨道我们加不了自定义剪辑,得新建自己用的。这个很简单。

[TrackClipType(typeof(TransformTweenClip))] //关联的Clip类型
[TrackBindingType(typeof(GameObject))] //绑定的数据类型。
public class TestTrack1 : TrackAsset
{
}

编译过后就可以在Timeline的窗口里创建这个轨道了。后面再给这个轨道关联我们的自定义剪辑。

主要就是几个属性的作用需要了解一下。

[TrackClipType(type))]
指定关联的Clip类型,如果一个都没有,在Track上右键菜单里就没有可创建的clip。

[TrackBindingType(type))]
指定绑定的数据类型。这样在Track上会出现对象选择器,绑定的数据对象会作为playdata参数传递给我们(后面会看到)。

 

此外还有

[TrackColor(0,255,0)]轨道颜色 是0~255的值

第二步 创建Clip数据

Timeline窗口里编辑的是数据,这个就是定义Clip的数据。数据和逻辑分离的设计,很好理解。

public class TestClip1 : PlayableAsset
{
    public Transform trans;
    public Vector3 start;
    public Vector3 end;
}

记得用[TrackClipType(typeof(TestClip1))] 把它在TestTrack1上关联。

第三步 创建Clip的行为

public class TestClip1Behaviour : PlayableBehaviour
{
    public TestClip1 data;
    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        base.ProcessFrame(playable, info, playerData);
        data.trans.localScale = Vector3.Lerp(data.start, data.end, (float)(playable.GetTime() / playable.GetDuration()));//Clip上的当前时间/总时间
    }
}

还需要让数据和逻辑关联起来,Unity不知道TestClip1对应的是TestClip1Behaviour。Unity采取的办法是让我们在数据里的一个虚函数里创建逻辑对象并返回。TestClip1需要加一点代码。

public class TestClip1 : PlayableAsset
{
    public Transform trans;
    public Vector3 start;
    public Vector3 end;

    //增加的代码如下:
    public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
    {
        return ScriptPlayable<TestClip1Behaviour>.Create(graph, new TestClip1Behaviour(){data = this});
    }
}

也很简单。

剪辑的行为对象在这个ScriptPlayable<T>里面,如果我们要获取其他剪辑行为对象,首先获取到的也是这个东西。通过T ScriptPlayable<T>.GetBehaviour()就可以获取到具体的行为对象了。这个后面做剪辑混合会用到。具体可以看手册。

编译结束后就可以去Timeline窗口里创建剪辑了。

小结

基本的剪辑扩展就完成了,功能都在Behaviour里。

扩展一 ExposedReference<T>

需要注意的是,上面为了省事,TestClip1里直接把Transform声明为变量了。但是Timeline存储后是一种资源,资源是不能直接引用场景里的东西的,也就是说trans字段的引用对象不会保存到对象。这里可以通过关闭场景然后再次打开来验证,Timeline文件上引用的场景对象会丢失。

为了解决这个问题,unity搞了个ExposedReference<T>类型来实现对场景里的东西引用。估计是用路径查找实现的,具体就没去翻了。只需要将定义改成这样就行了:

public ExposedReference<Transform> trans;

//获取真正trans对象的代码为:
//trans.Resolve(playable.GetGraph().GetResolver())

详情可以看这里:

【Unity学习笔记】ExposedReference类的初识 + 自定义Timeline轨道初识-CSDN博客

扩展二 剪辑混合

剪辑混合是一条Track里的多个剪辑发生过渡时,根据各个剪辑的权重用户自己算出一个最终的值。这个过程Unity不会自动做,要撸代码。注意混合是Track层面的事情,不是Clip里的事,要遍历多个Clip来计算。

总共可分两步。第一步创建混合行为代码。

public class TestTrack1Mixer : PlayableBehaviour
{
    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        base.ProcessFrame(playable, info, playerData);
        var inputCount = playable.GetInputCount();
        var scale = Vector3.zero;
        for(int i = 0; i < inputCount; i++)
        {
            var scriptPlayable = (ScriptPlayable<TestClip1Behaviour>)playable.GetInput(i);
            var bhv = scriptPlayable.GetBehaviour();//如果不是TestClip1Behaviour,这里会返回null。设计时注意即可。
            float weight = playable.GetInputWeight(i);
            //Behaviour是在包含它的ScriptPlayable<T>里跑的,时间从scriptPlayable这个变量获取,而不是函数传入的playable变量
            scale += weight * Vector3.Lerp(bhv.data.start, bhv.data.end, (float)(scriptPlayable.GetTime() / scriptPlayable.GetDuration()));
        }

        //这里用了playerData,就是[TrackBindingType(typeof(GameObject))] 绑的
        var go = playerData as GameObject;
        go.transform.localScale = scale;
    }
}

这里混合后最后控制的对象是playerData传入的。从遍历到的TestClip1Behaviour上取也行,但是不如这样方便。

第二步在Track1Asset里创建这个混合器。

[TrackClipType(typeof(TransformTweenClip))] //关联的Clip类型,如果一个都没有,在Track上右键菜单里就没有可创建的clip。
[TrackBindingType(typeof(GameObject))] //绑定的数据类型。
public class TestTrack1 : TrackAsset
{
    //新增的代码
    public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
    {
        return ScriptPlayable<TestTrack1Mixer>.Create(graph, inputCount);
    }
}

扩展三 自定义信号

继承自SignalEmitter就行了。

public class TestSignal : SignalEmitter
{
    public string arg;
}

编译通过后,Timeline编辑器里就会显示自己的信号。

既然已经自定义信号了,那么也得自定义一个信号接收器了,自带的信号接收器SignalReceiver不能处理自定义信号。代码如下,也很简单。

public class TestSignalReceiver : MonoBehaviour, INotificationReceiver
{
    public void OnNotify(Playable origin, INotification notification, object context)
    {
        var s = notification as TestSignal;
        Debug.Log(s.arg);
    }
}

系统自带的信号发送和接收,相当于就是把一个资源文件作为信号参数传递,然后根据信号参数调用对应处理函数,大多数情况下用系统自带的就够用了。

其他

一般会将控制的场景对象作为数据绑定传递到Clip和Mixer,作为字段放在Clip里会有引用丢失问题。

参考

Timeline:实用指南

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

qt介绍信号槽一

信号和槽时qt框架中事件处理的一种机制&#xff0c;qt是基于窗口框架的程序&#xff0c;基于窗口框架额程序都是基于事件的&#xff0c;本质信号对应的就是一个事件&#xff0c;槽对应事件处理的动作。信号槽机制类似于设计模式力的观察者模式。观察者模式就是我一直观察是否有…

【linux】解决 Linux 系统中 root 用户无法打开图形界面问题

【linux】解决 Linux 系统中 root 用户无法打开图形界面问题 问题描述&#xff1a; 在 Linux 系统中&#xff0c;当我们远程SSH尝试以 root 用户身份运行需要图形界面的应用程序时&#xff0c;可能会遇到以下错误信息&#xff1a; MoTTY X11 proxy: Unsupported authorisati…

【开源项目-爬虫】Firecrawl

看到其他项目引用了这个项目 Firecrawl 用免费额度试了一下&#xff0c;这个项目和之前的 https://r.jina.ai/ 很像&#xff08;类似的还有 https://www.scrapingbee.com/&#xff1f;&#xff09;&#xff0c;将爬取到的网页转换为 markdown 格式&#xff0c;这样大语言模型用…

【已解决】电脑空间告急?我的 Ollama、Docker Desktop软件卸载清理全记录

一、卸载 Ollama、Windows SDK 和 Docker Desktop的原因 最近电脑总提示空间不足&#xff0c;前段时间想本地部署大模型而安装的 Ollama、多个 Windows SDK 以及暂时用不到的 Docker Desktop 占用了不少空间。果断动手卸载&#xff0c;现在把过程整理成博客&#xff0c;分享给同…

便利店商品推荐数字大屏:基于python和streamlit

基于python和streamlit实现的便利店商品推荐大屏&#xff0c;针对选择困难症消费者。 import streamlit as st import pandas as pd import numpy as np import altair as alt from datetime import datetime, timedelta import time# 模拟数据生成 def generate_data():np.ra…

OpenAI智能体初探:使用 OpenAI Responses API 在 PDF 中实现检索增强生成(RAG)

大家好,我是大 F,深耕AI算法十余年,互联网大厂技术岗。 知行合一,不写水文,喜欢可关注,分享AI算法干货、技术心得。 欢迎关注《大模型理论和实战》、《DeepSeek技术解析和实战》,一起探索技术的无限可能! 引子 在信息爆炸的时代,从大量 PDF 文档中快速准确地检索信息…

【实战-解决方案】Webpack 打包后很多js方法报错:not defined

问题分析 在不打包的情况下&#xff0c;方法&#xff08;如 checkLoginStatus、filterSites、initProgressBar 等&#xff09;可以正常运行&#xff0c;而经过 Webpack 打包后报 is not defined 错误&#xff0c;通常有以下几个可能的原因&#xff1a; 全局变量丢失 在 Webpac…

【大模型基础_毛玉仁】2.3 基于 Encoder-only 架构的大语言模型

更多内容&#xff1a;XiaoJ的知识星球 目录 2.3 基于Encoder-only 架构的大语言模型2.3.1 Encoder-only 架构2.3.2 BERT 语言模型1&#xff09;BERT 模型结构2&#xff09;BERT 预训练方式3&#xff09;BERT 下游任务 2.3.3 BERT 衍生语言模型1&#xff09;RoBERTa 语言模型2&a…

链表所有节点值的和

class Node:# 节点类&#xff0c;每个节点包含数据(data)和指向下一个节点的引用(next)def __init__(self, data):self.data data # 存储节点的数据self.next None # 指向下一个节点&#xff0c;默认值为None&#xff0c;表示没有下一个节点class LinkedList:# 链表类&…

STM32 F407ZGT6开发板

#ifndef _tftlcd_H #define _tftlcd_H #include "system.h" //定义LCD彩屏的驱动类型 可根据自己手上的彩屏背面型号来选择打开哪种驱动 //#def…

c# txt文档的实时显示,用来查看发送接收指令

通讯历史按钮 private void uiButton1_Click(object sender, EventArgs e){try{logf new logF();logf.Show();}catch (Exception){throw;} }主页面关闭函数&#xff08;点击保存就为true true就不删除&#xff09; private void page1_FormClosed(object sender, FormClos…

Excel 数据转换为SQL语句

文章目录 一、制作公式二、示例图 一、制作公式 1、找一列空白的&#xff0c;选中一个单元格&#xff0c;输入""&#xff0c;在双引号中写入INSERT语句脚本&#xff0c;然后回车。 // 数字代表行数 “INSERT INTO PayList (product, rmb) VALUES (”&A10&“…

SpringMVC (一)基础

目录 SpringMVC 一 简单使用 1 新建模块选择指定参数 2 创建实现类 3 将项目启动 4 运行结果&#xff1a;在浏览器当中响应执行 二 RequestMapping 三 请求限定 SpringMVC SpringMVC是Spring的web模块&#xff0c;用来开发Web应用&#xff0c;SpringMVC应用最终作为B/…

windows第十二章 MFC控件常用消息

文章目录 控件反射消息机制文本框控件EN_CHANGE消息EN_UPDATE消息EN_SETFOCUS消息EN_KILLFOCUS消息EN_MAXTEXT消息EN_ERRSPACE消息EN_HSCROLL消息 按钮控件BN_CLICKED消息BN_DOUBLECLICKED消息BN_SETFOCUS消息BN_KILLFOCUS消息 单选按钮BN_CLICKED 消息 复选框BN_CLICKEDBN_DOU…

基于C语言的简单HTTP Web服务器实现

1. 概述 本案例使用C语言实现了一个简单的HTTP服务器&#xff0c;能够处理客户端的GET请求&#xff0c;并返回静态文件&#xff08;如HTML、图片等&#xff09;。在此案例中案例&#xff0c;我们主要使用的知识点有&#xff1a; Socket编程&#xff1a;基于TCP协议的Socket通信…

ZYNQ初识13(zynq_7020)hdmi和串口板载功能的验证

&#xff08;1&#xff09;另&#xff1a;首先需要确认供电模块&#xff0c;电压转换模块没有问题&#xff0c;测量后上电防止出现短路。通过vivado下载bit流文件检测JTAG下载口是否正常&#xff0c;如可正常检测&#xff0c;才可进行下一步验证。 &#xff08;2&#xff09;以…

ollama下载的DeepSeek的模型(Model)文件在哪里?(C盘下)

目录 一、下载大模型&#xff08;DeepSeek&#xff09; 2. 安装 Ollama 3. 检查安装是否成功 二、拉取大模型&#xff08;DeepSeek&#xff09; 1. 打开命令行 2. 下载模型 3. 测试下载 4. 等待下载完成 三.模型存放路径 这个位置&#xff01;&#xff01; 在人工智能…

docker的anythingllm和open-webui压缩包分享(国内镜像拉取,百度云压缩包分享)

文章目录 前言第一部分&#xff1a;镜像获取&#x1f680; 方式一&#xff1a;切换国内下载镜像✅1. 下载anythingllm✅ 2. 下载open-webui &#x1f680;方式二&#xff1a;下载我分享的百度云✅ anythingllm压缩包百度云链接❎ open-webui压缩包 第二部分&#xff1a;下载之后…

父组件中循环生成多个子组件时,有且只有最后一个子组件的watch对象生效问题及解决办法

提示&#xff1a;父组件中循环生成多个子组件时&#xff0c;有且只有最后一个子组件的watch对象生效问题及解决办法 文章目录 [TOC](文章目录) 前言一、问题二、解决方法——使用function函数代替箭头函数()>{}总结 前言 ‌‌‌‌‌问题&#xff1a;子组件用that解决watch无…

求递增子序列LIS的两种方法

文章目录 前言一、普通动态规划&#xff08;DP&#xff09;求解LIS1.DP思路2.DP的状态定义与转移方程3.DP的时间与空间复杂度4.DP代码实现5.DP的图文示例 二、贪心 二分查找求解LIS1.思路分析2.贪心 二分的时间与空间复杂度 三. 模板题讲解1.洛谷B3637 最长上升子序列1.dp写法…