TiXL 图构建实战指南:子图封装、上下文变量与流程控制
2026/9/18 15:10:31 网站建设 项目流程

TiXL 图构建实战指南:子图封装、上下文变量与流程控制

【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3

本文是 TiXL(Tooll 3)中关于构建 Operator 图的实战技术指南,围绕官方 FAQ 文档 FaqBuildingContent.md 展开,系统讲解子图(subpatch)的拆分时机、基于 Evaluation Context 的全局变量机制,以及时间条件、分支切换等流程控制的四种实现方案。读完本文,你将掌握如何在实时图形项目中把重复的 3D 场景、特效、排版与数学逻辑封装为可复用算子,并学会用粒子年龄驱动缩放等典型技巧。

何时创建子图(Sub-Graph)

“是否应该把一段图封装成子图”本质上属于个人偏好问题,但以下信号可以作为判断依据:

  • 重复出现超过 2 次:当你发现图的某一部分被重复放置多次(两次以上)时,这通常是最强烈的抽象信号。常见的可泛化对象包括:
    • 场景:例如一个反复出现的 3D 元素;
    • 特效:例如一组组合使用的点修改器(point modifiers);
    • 排版元素:例如开场标题中反复显示的名字;
    • 数学逻辑:例如计算某个元素尺寸的公共表达式。
  • 单个嵌套算子太小:一个仅含 1 个算子的“子图”大概率过小了。大多数算子的内部规模在2 到 30 个算子之间。
  • 主输出即类型:绝大多数算子只有一个主输出,其输出类型直接决定了该算子在画布上的颜色;只有极少数算子带有额外输出(例如第二张贴图纹理)。
  • 参数化成本极低:为封装后的子图添加参数(例如前面“标题”案例中的 Names 参数)非常快,你可以随时修改、重排或重命名这些参数,这进一步降低了抽象的门槛。

变量(Variables)机制

变量如何工作

在 TiXL 中,变量是Evaluation Context(求值上下文)的组成部分。从源码看,上下文内部按类型用字典存储变量,见 EvaluationContext.cs:

  • Dictionary<string, bool> BoolVariables
  • Dictionary<string, int> IntVariables
  • Dictionary<string, float> FloatVariables
  • Dictionary<string, object> ObjectVariables(用于浮点、整数之外的对象)
  • Dictionary<string, string> StringVariables

每次求值周期开始(Reset()),这些字典都会被清空重建,见 EvaluationContext.cs,因此变量是“每帧有效”的临时通信手段,而不是跨帧持久化存储。

赋值与读取:SetFloatVar / GetFloatVar

由于变量随求值上下文传播,你需要在图中尽早赋值——即靠近最终输出的“右侧”,这样位于图“左侧”(下游)的子图才能读到它。实际操作符位于flow/context目录,对应源码文件为:

  • SetFloatVar.cs:写入浮点变量,输入包括VariableNameFloatValue、可选的SubGraph(Command 输入)以及ClearAfterExecution。其实现逻辑是:若SubGraph有连接,则先写入新值、执行子图,执行完毕后再恢复此前保存的旧值(这正是“子图中覆盖变量后自动恢复”的来源);若子图未连接,则直接写入context.FloatVariables[name]
  • SetBoolVar.cs、SetIntVar.cs:分别对应布尔与整数变量。
  • GetFloatVar.cs:读取浮点变量。读取器还实现了ICustomDropdownHolder,在编辑器里会基于当前上下文中已存在的变量名生成下拉候选列表;同时提供FallbackDefault输入,作为变量不存在时的回退值,避免“取不到值”导致参数归零。

典型应用场景如文档所述:定义一批全局变量,让各个子图根据 MIDI 输入等信息选择不同的变体(variant)——用SetFloat/SetBool等提前写入,下游子图用GetFloatVar/GetBoolVar读取即可。

子图中的覆盖与恢复

文档强调“变量可以在子图中被覆盖(先前的值会被恢复)”。这一点在 SetFloatVar.cs 的实现中得到印证:当SubGraph有输入连接时,代码用TryGetValue保存previous,子图求值完成后,若存在旧值则恢复旧值,否则根据ClearAfterExecution决定是否移除该变量。这保证了变量赋值具有词法作用域的语义——内层子图临时改值不会污染外层图。

流程控制:条件逻辑的四种方案

文档以if(time >= 16.0 && time < 18.0) { ... }这类演出编排需求为例,给出了四种实现思路,按推荐程度排序:

方案一:TimeClips(最推荐)

TimeClips是最方便的条件控制方式,尤其是当你正确设置 BPM 并启用时间线的bar-raster(小节栅格)模式后,可以享受精确的吸附、剪切等时间线编辑能力。核心算子 TimeClip.cs 的求值逻辑为:

  1. 根据当前时间LocalFxTime与 clip 的TimeRange计算归一化时间,并写入上下文变量_normalizedTime(供 clip 内部内容读取,实现区域映射);
  2. 依次对连接的 Command 执行PrepareActionGetValueRestoreAction,即只在 clip 时间窗口内激活其内容。

底层的时间映射由 Core/Animation/TimeClip.cs 提供:MapTimelineToSource/MapSourceToTimeline实现时间线与源时间区间的仿射映射,SpeedGetPlaybackSpeed处理变速播放,SourceUnit则区分源区间以 Bars 还是 Seconds 计时(音乐类内容用 Bars、音视频等墙钟媒体用 Seconds)。所以 TimeClips 不仅能做“开/关”,还能做时间重映射与变速。

方案二:Compare + Execute/Group 的 Enabled 参数

[Compare]产生布尔结果,配合布尔逻辑去驱动[Execute][Group]Enabled参数。当条件为假时,对应分支整体不被求值,效果等同于停用。

方案三:动画 [Switch] 的索引

[Switch]算子(见 Switch.cs)通过Index输入选择求值哪个分支,其行为有明确的边界值语义:

  • 索引指向已连接图的序号:只求值该分支,其余分支不会被求值,这与“停用其他分支”等价;
  • -1全部禁用(源码中index == -1时直接返回,不执行任何命令);
  • -2全部启用(源码中遍历所有 command 依次执行并统一做恢复)。

从源码看,Index为其它值时会取模(index %= commands.Count)以支持循环切换,并提供Count输出(已连接命令数)与OptimizeInvalidation(仅失效被选中索引,提升多分支下的求值性能)。

方案四:禁用算子(不推荐用于演出)

直接禁用算子(连同其完整子图)虽然简单,但无法被动画化或通过参数控制,因此不适合需要随时间切换的演出场景。

实战:用粒子年龄驱动缩放

文档给出了一个经典案例:把粒子年龄(age,从 0 增长到 1)直接作为缩放因子时,粒子会在“出生时尺寸为 0、死亡时尺寸最大”,这通常与预期相反。期望的行为往往是:粒子从 0 快速膨胀到最大尺寸,随后再淡出回 0。

推荐链路为:

[ParticleSystem] → [MapPointAttributes](Input Mode 设为 F1)

MapPointAttributes.cs 的输入模式枚举(InputModes)包括BufferOrderF1F2Random,把F1(粒子的第一个浮点属性通道,典型即年龄)作为驱动源。真正实现“快速膨胀再淡出”需要组合其映射与写入模式:

  • Mapping(映射模式)Centered(以 0.5 为中心)、ForStartPingPongRepeatUseOriginalW。其中PingPong可以让 0→1 的输入折返为 0→1→0,天然形成“先增后减”的形状;
  • WriteTo(写入目标):可写回F1F2Scale——要实现尺寸变化,应写入Scale
  • WriteMode(写入方式)Replace(替换)、Multiply(相乘)、Add(叠加),用于与粒子已有的缩放值组合;
  • MappingCurve:接受一个Curve输入,可以自定义非对称的缩放包络(例如快速上升、缓慢衰减的 ADSR 式曲线),这是实现“很快膨胀到最大、再淡出到 0”最灵活的手段;
  • 其余输入如RangePhaseStrengthStrengthFactorGradientValueTexture可用于进一步调整映射范围、相位偏移与颜色输出。

粒子数据本体由 ParticleSystem.cs 承载,包含ParticleBufferSpeedFactorIsResetInitializeVelocityFactor等字段,MapPointAttributes 读取其缓冲并逐粒子改写属性,输出新的BufferWithViews供渲染使用。文档中所举的[ParticleSystem] → [MapPointAttributes]即是在粒子缓冲上做属性重映射的标准管线。

小结

构建高质量 TiXL 图的核心方法论可以浓缩为三点:用子图消化重复(2~30 个算子的封装粒度)、用上下文变量做跨子图通信(在靠近输出的右侧赋值,子图内覆盖自动恢复)、用 TimeClips / Compare / Switch 做时间与分支控制(牢记 Switch 的-1全关、-2全开语义)。在此基础上,粒子等数据对象的属性重映射(如年龄驱动缩放)只是 MapPointAttributes 这类算子对缓冲属性的常规操作,组合好 Mapping、WriteTo 与 WriteMode 即可得到丰富的动态效果。

【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询