TiXL 图像合成变换(ImageComposeTransform)上下文机制设计解析:让 UV 变换在整个纹理图内免费生效
【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3
本文解读 TiXL 仓库
.agentic/Plans/Plan_ImageComposeTransform.md中的工程计划:如何在EvaluationContext上引入一个中立的ImageComposeTransform上下文字段,让纹理消费型算子(texture-consuming ops)在采样/渲染时统一读取并应用它,从而用一个TransformImage算子即可为其整棵子树施加偏移、缩放、旋转、镜像、染色、透明度与混合——全程零额外渲染 pass。读者将理解这套机制的完整设计(默认值约定、参与规则、组合顺序、分批迁移策略、风险与缓解),并结合仓库中EvaluationContext、现有TransformImage算子及其.t3配置、视频工作计划的上下文约定,掌握其落地的技术路径与适用边界。注意:该计划当前处于Drafted / Deferred(草案、已延期)状态,文中凡属计划设想的内容均已明确标注。
一、计划背景:从视频合成工作中拆出的一项横向工程
ImageComposeTransform计划源自视频工作(Plan_VideoClipPlayer.md)的延伸。视频计划为了支持多片段合成,需要一种"图像级上下文变换"约定:视频算子(VideoClipPlayer的 blit、VideoClip、TransformImage)在EvaluationContext上引入并消费同一个ImageComposeTransform字段。视频工作只要求它自己的算子遵守该字段即可推进,并不依赖本计划。
而本计划(Plan_ImageComposeTransform.md)的目标是把这一机制的消费范围推广到每一个纹理消费算子,使"免费的 UV 变换"(free UV transforms)在整个图中普遍生效。因此它被定位为一项横切(cross-cutting)的大型工程,覆盖上百个算子,而非某一个具体功能。
从仓库现状看,该上下文字段尚未出现在 EvaluationContext.cs 中——当前EvaluationContext已携带 3D 侧的三套矩阵(CameraToClipSpace、WorldToCamera、ObjectToWorld,见 EvaluationContext.cs)、ForegroundColor、ContextTextures、FloatVariables/IntVariables等上下文数据,但尚无ImageComposeTransform属性,与本计划"Deferred(已延期)"的状态一致。这反过来印证了计划文档的定位:这是一份待实施的设计蓝图。
二、核心思想:让上下文替算子"记住"变换
2.1 一个字段,一个默认值
计划的核心设想是:在EvaluationContext上携带一个ImageComposeTransform结构,并赋予它一个中立且有意义(neutral, meaningful)的默认值:
| 组成 | 中立默认值 | 含义 |
|---|---|---|
| UV 变换 | 单位矩阵(identity) | 不改变采样坐标 |
| 颜色 / 染色 | 1 | 不染色 |
| 透明度(opacity) | 1 | 完全不透明 |
| 混合模式 | 正常混合(normal blend) | 标准叠加 |
| 采样器 | 默认采样器 | 常规过滤/寻址 |
纹理消费型算子在采样或渲染时读取该字段并应用它。这与 3D 侧 Scene[Transform]携带世界矩阵(world matrix)的心智模型完全一致:变换作为上下文沿评估树向下传递,子图里的算子无需各自接线,就能感知到父级施加的变换。
2.2 一个算子管一整棵子树
计划中设想的TransformImage是一个通用的子图修饰算子(不限于视频):它在其子图求值期间修改context.ImageComposeTransform,因此子树中的每一个图像/纹理算子都会拾取到累积后的变换——不需要任何逐算子接线(no per-op wiring)。
这正好与仓库中现有的 TransformImage.cs 形成对比。当前仓库里的TransformImage是一个传统单入单出的 Texture2D→Texture2D 变换算子:输入为Image、Offset、Stretch、Scale、Rotation、Resolution、ResolutionFactor、GenerateMips、Filter、WrapMode(见 TransformImage.cs),本质上是一个会产出中间纹理的独立变换节点。而计划中的TransformImage是上下文修饰符形态——它不产出新的纹理,只改写上下文,让子树内的所有采样在 shader 内完成变换。两者同名不同构,读者在阅读本计划时应注意区分(后者属于待实施的未来形态)。
三、为什么值得做:三个核心论据
计划给出了三点理由,构成该机制的价值判断:
- UV 变换在采样时几乎是免费的。偏移 / 缩放 / 旋转 / 镜像如果施加在采样时刻,就只是算子已运行的 shader 内部的一次坐标变换——没有额外的渲染 pass、没有中间渲染目标。而链式串联一个专用的变换算子,需要一次全屏 blit(full-screen blit)的成本。染色 / 透明度 / 混合同样可以折叠进同一次采样。
- 一套机制,全图生效。
TransformImage(如同[Transform])变换的是整个图像子图;算子不再需要各自暴露 offset/scale/rotate 输入。 - 与 3D 侧保持一致。使用与 Scene
[Transform]相同的思维模型,降低学习与维护成本。
四、安全默认原则:让 100+ 算子的推广可增量进行
计划特别强调了一个使工程"可推进"(tractable)的性质——Safe by default(默认安全):
- 由于上下文默认值是中立的(identity / one),且只有子树中的
TransformImage会改变它,现有项目在引入TransformImage之前完全不受影响。 - 不存在对当前图的行为迁移(behavioral migration)——采纳是纯增量的:未迁移的算子像今天一样忽略(中立的)上下文;已迁移的算子仅在上下文非中立时才会生效。
- 这正是一个覆盖 100+ 算子的推广可以**分批进行、无需 flag day(统一切换日)**的原因:任何时候都可以安全地发布部分迁移成果。
从计划随后列出的实施节奏看,这一原则贯穿始终:未迁移的算子靠"默认中立"继续正常工作,已迁移的算子靠"非中立才生效"保证行为可预期。
五、范围与成本:工作量的大头在哪里
计划明确指出,本工程的主体工作量是约 100+ 个纹理消费型算子——包括它们的HLSL 采样器以及C# 常量接线(constant wiring)。每一个算子都需要:
- 把上下文变换传入自己的 shader;
- 在采样时刻应用该变换。
这意味着它不像视频计划那样集中在少数几个新算子,而是一场覆盖全图既有算子的系统性改造。这也是它被标记为"大型横切工程"并延期的直接原因。
六、落地策略:共享 helper、明确规则、按类分批
6.1 共享 helper,而不是逐个算子重新发明
计划给出的第一条策略是共享 helper,保证"一处把数学做对,处处复用":
- HLSL 侧:一个 include 文件,例如
SampleWithComposeTransform(...),封装"采样 + 应用上下文变换"的逻辑; - C# 侧:一个 helper 把上下文
ImageComposeTransform打包(pack)进常量缓冲区(constant buffer)。
算子迁移时只需把自己的采样调用切换到该 helper,即可获得统一的行为与最小的逐算子改动量。这一设计也直接服务于风险章节中"常量缓冲区布局一致性"的缓解:由共享 helper 统一打包,就避免了上百个算子各自定义布局导致的不一致。
6.2 定义参与规则(participation rule)
并非所有算子都该遵守该字段。计划要求明确参与边界,让采纳变成机械操作而非逐案判断:
- 参与:纹理采样 / 绘制类算子——滤镜(filters)、blit、绘制(draws)、读取纹理的生成器(generators);
- 不参与:纯数据 / 非空间(pure-data / non-spatial)算子。
从仓库算子布局可以观察到这一边界的自然分界:图像类算子集中在 Operators/Lib/Symbols/image/ 下(含analyze、color、fx、transform、use等子目录),其中fx(滤镜/扭曲)、use(采样使用)等即属于计划所指的"采样/绘制"参与者,而纯数值、数据结构类算子则明显不属于空间变换范畴。
6.3 与算子自身变换输入调和:ambient ∘ local
许多图像算子已经自带 offset/scale/rotate 输入(现有TransformImage即是例子)。计划需要约定组合规则:上下文变换是从祖先继承来的"环境变换"(ambient transform),与算子自身的局部输入(local)组合,即:
最终变换 = ambient ∘ local这与[Transform]沿场景树向下组合的方式一致。这一条约定了"继承自祖先的变换"与"算子本地参数"谁先谁后,是避免视觉回归(见风险章节)的关键语义。
6.4 按类别增量迁移(Incremental, by category)
计划的实施分为若干阶段:
- Phase 1:字段本身 + 共享 helper + 视频算子(与视频计划重叠);
- Phase 2+:按批次迁移纹理算子,顺序为生成器(generators)→ 滤镜(filters)→ 渲染器(renderers),每批可独立测试。
每批都靠"默认安全"性质保证未迁移算子继续工作。这种"小步、可测、可回退"的节奏,与计划文档将其定性为可增量推进的工程完全一致。
七、风险与缓解
计划列出了三类主要风险及其对策:
| 风险 | 缓解措施 |
|---|---|
| 视觉回归:算子在错误的坐标系或顺序下应用变换 | 中立默认值(无变换 ⇒ 无变化)+ 每批视觉测试 |
| 常量缓冲区布局一致性:众多算子各自定义布局导致漂移 | 共享 helper 统一打包与布局 |
| 热路径纪律:应用必须零分配、且折叠进现有采样(不产生额外 pass) | 遵循引擎的每帧规则,强制在采样内完成 |
其中"热路径纪律"与 TiXL 引擎一贯的"每帧零分配(no-per-frame-allocation)"约束一致——视频计划中_ProcessVideoClips复用List/HashSet避免每帧分配的做法(见 Plan_VideoClipPlayer.md)正是同一纪律的体现。
八、与视频工作的关系:约定的具体形态
Plan_VideoClipPlayer.md中的Compose params &TransformImage(the context convention)一节给出了该机制在视频场景下的具体约定,可作为本计划第一消费者的实现蓝图:
EvaluationContext携带ImageComposeTransform,默认中立(identity 矩阵、color = 1、opacity = 1、normal blend);不做特殊处理的叶子算子不触碰它。TransformImage是通用子图修饰符:像 Scene[Transform]一样,在子图求值期间改写context.ImageComposeTransform,子树中的每个图像 /VideoClip都会拾取累积变换——这也是"接线(wired)剪辑"获得外部/图驱动变换的方式。VideoClip携带自己的完整合成参数集(transform / color / opacity / blend / sampler)作为可动画输入。作为叶子节点,它读取当前上下文、组合自身参数,并注册{frame, TimeClip, finalTransform}供播放器 blit——它不写上下文字段,只有变换算子才写。- 当不存在祖先
TransformImage(上下文中立)时,VideoClip只用自己的参数——这是日常路径,也是虚拟(自动收集 auto-collected)路径。自动收集的剪辑位于任何TransformImage子树之外,因此只能通过自身参数变换——这一规则被机制本身强制,而非特判。
该计划文档还明确了两者的解耦关系:视频工作不被本计划阻塞——视频合成只需要自己的算子遵守该字段即可先行落地;本计划随后将消费推广到其余纹理算子,"把免费的 UV 变换开遍全图"(turning 'free UV transforms' on everywhere)。
九、仓库现状佐证:可继续深挖的路径
- 上下文载体:EvaluationContext.cs —— TiXL 的求值上下文,已含 3D 矩阵(
CameraToClipSpace/WorldToCamera/ObjectToWorld,L123-L125)、ForegroundColor、ContextTextures等;ImageComposeTransform字段按计划将在此落地。 - 同名现有算子:TransformImage.cs 与 TransformImage.t3 —— 当前为传统 Texture2D→Texture2D 变换算子,其
.t3配置显示默认值:Stretch=(1,1)、Scale=1.0、Offset=(0,0)、Rotation=0.0、Resolution=(0,0)、ResolutionFactor=(1,1)、Filter=MinMagMipLinear、WrapMode=2(Clamp 系)、GenerateMips=false,并引用Lib:shaders/img/fx/TransformImage.hlsl(见 TransformImage.t3)。 - 视频计划中的上下文约定:Plan_VideoClipPlayer.md —— 首批消费者的行为定义与实施状态(Phase 1/2 已完成,含
_ProcessVideoClips、LayerIndex排序、每剪辑Color/BlendMode等)。 - 示例:TransformImageExample.cs —— 官方示例中对
TransformImage的使用入口。
十、总结:一份"默认安全、可增量、共享 helper"的图级改造蓝图
ImageComposeTransform计划把视频合成工作中自然生长出的上下文约定,升格为一项覆盖全图纹理算子的系统性改造。它的设计精髓在于三点:
- 中立默认值消除了对既有项目的任何行为迁移,使 100+ 算子的推广可以无限分批;
- 共享 helper + 明确参与规则 + ambient ∘ local 组合约定,把逐算子改造从"每处判断"降为"机械替换";
- 与 3D
[Transform]同一心智模型,让"变换向上游合成"这一看似特殊的语义成为惯例而非特例。
对读者而言,理解这份计划不仅有助于阅读 TiXL 未来的提交历史,也能复用于任何"上下文携带渲染状态、叶节点采样时消费"的实时图形引擎架构设计。当前该计划处于延期状态,仓库中的落地证据主要在视频工作一侧(VideoClipPlayer/VideoClip的上下文约定),全图推广的 HLSL helper(如SampleWithComposeTransform)与EvaluationContext.ImageComposeTransform字段尚待后续实施。
【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考