ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

TiXL (t3) 实战笔记:SDF 文字混合、文字描边粒子发射器与红绿立体相机管线

TiXL (t3) 实战笔记:SDF 文字混合、文字描边粒子发射器与红绿立体相机管线 TiXL (t3) 实战笔记SDF 文字混合、文字描边粒子发射器与红绿立体相机管线【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3本文基于 2026-08-24 的 TiXL 社区 Meetup 记录时长 4 小时 34 分完整纪要见 .help/references/video-analysis/CNvtNwG2Mls.md围绕三块实战内容展开如何用模糊文本贴图与规范 SDF 构建可混合的文字距离场、如何用文字描边点生成带寿命属性映射的粒子发射器、以及如何用双偏移相机搭出红绿anaglyph立体管线并现场给 [CamPosition] 增加相机引用输入。读完后你能掌握 TiXL 中 shader-graph 距离场操作符的组合方式、player 导出与 shader 缓存机制、粒子属性缓冲的编程模型以及评估上下文失效/缓存机制的关键细节。一、文字 SDF 混合从高度图伪 3D 到规范 2D 文字场1.1 高度图路线模糊文本贴图构建伪 3D Logo 场会议开头0:07→9:20先走了一条非规范但出效果快的路线渲染文字到方形 RenderTarget0:07→1:50把 [Text] 输出到方形 RenderTarget再用 [FastBlur] 柔化得到灰度图作为高度/深度贴图用来构建伪 3D Logo 场。高度图 SDF 化并镜像1:50→2:56把模糊后的文字图喂给 [HeightMapSdf] 作为高度图输入可以得到近似的挤出 3D外观再用 [ReflectField] 在向上法线的平面上反射得到落地感形状。与简单形体求交裁剪2:56→3:45用 [CombineSDF] 把文字高度场与 [SphereSDF] 求交来裁剪形状同时 [RaymarchField] 的 max-slope最大斜率调大会显著增加光线步进次数——用速度换取病态场上更少的伪影。上材质3:45→4:05短暂用 [SetSDFMaterial] 给光线步进的文字场一个表面材质随后进入混合环节。1.2 [BlendSDFWithSDF] 的实现原理[BlendSDFWithSDF]4:05→5:15的作用在一个空间范围内把场 A 交叉淡出到场 B——例如让一个平面扫过场景从一侧把一种形状扫成另一种。当前仓库的实现见 Operators/Lib/Symbols/field/combine/BlendSDFWithSDF.cs操作符要求3 个场输入FieldA、FieldB与WeightField遮罩场不满足时通过IStatusProvider报 Requires 3 input fields见 L16-L19注入的 HLSL 核心是sdfBlendByMask(dA, dB, dM, w)L33-L63当过渡宽度w0时做精确切换——(A ∩ {dM≤0}) ∪ (B ∩ {dM≥0})即max(dA, dM)、max(dB, -dM)再取minw0时把 max/min 换成多项式 smooth min/maxk为过渡宽度单位是距离两个图参数 [GraphParam]RangeL131-L133与OffsetL135-L137生成代码里用smoothstep(0,1,(weight.w - Offset)/Range)驱动位置向 B 场插值L102-L105。为什么形状会在混合中缩水5:17→6:55线性插值两个距离函数本质是对差别很大的距离值取平均而高度图派生的文字场并不是良构well-formedSDF会让这类混合行为不可预测。用 [VisualizeFieldDistance] 可以快速检查距离场分布6:55→7:30检查完后把整个设置收进 [Group]。把一次性扫过变成循环7:30→9:20用 [RepeatAxis] 沿一个轴镜像重复混合平面再用 [Translate] 平移它扫过过渡就变成可循环动画。两个典型坑混合范围Range开太大一切会熔成实心团块——范围要调小要得到锐利结果需要规范的 2D 文字 SDF 与体求交而不是混合劣质的高度场9:49→11:05。纹理派生场的边缘伪影会持续存在光线步进无法在量化后的距离台阶之间插值16-bit 贴图只部分缓解改用 MSDF 采样可行但配置繁琐22:05→25:05。1.3 规范路线JumpFloodFill → Image2dSDF → BoxSDF会话给出了正确的转换链11:49→12:4020:15→22:05用 [JumpFloodFill] 把渲染出的文字图转成可用距离纹理。仓库实现见 Operators/Lib/Symbols/image/generate/misc/JumpFloodFill.cs输入ImageTexture2D与MaxIterationCountint输出ImageOutputTexture2D。把距离纹理接进 [Image2dSDF]。当前源码见 Operators/Lib/Symbols/field/generate/sdf/Image2dSDF.cs输入SdfImageTexture2D、SdfScale、ImageSizeVector2、Offsetfloat。结果是一个无限延展的文字板infinite text slab。用 [BoxSDF] 与该无限文字板求交并把 Box 的 Z 尺寸缩小得到有界、可读的 3D 文字体。配套示例可参考 Operators/examples/Symbols/lib/field/generate/Image2dSDFExample.cs。JumpFloodFill 的关键限制27:20→28:10它只产生外侧距离正值字母在需要内侧负值距离的混合里熔不起来临时解法是跑两遍 flood fill带符号输出参数已列入愿望清单。循环形态文字28:10→30:00横向扫动混合平面同时在周期完成时用触发器切换下一段文字即可得到持续变形的文字循环把平面换成生长的立方体或竖直运动的平面则可以让文字生长或收缩。[MockStrings]26:18→27:20可作为随机占位组名的来源来驱动这种文字过渡。1.4 性能与变体技巧只在内容变化时重算昂贵分支30:00→32:55把时间转成整数[FloatToInt]用 [HasIntChanged] 门控 execute-update 标志让昂贵纹理分支仅在内容真正变化时重算代价是每次变化掉一帧。NoiseDisplaceSDF 昂贵33:28→34:20给场混合加入有机扭曲但 3D 噪声在每个光线步进点都会重新求值建议考虑比完整 Perlin 噪声更便宜的方案。TransformField 旋转变体34:36→35:20把混合平面绕 Z 旋转竖直擦除即变为上升的对角擦除过渡更有意思。多字母 SDF 的编译成本1:14:40→1:15:55用 SDF 构建大量 3D 字母会让场景在 shader 编译上停滞很久这也是该次演示改用 DCC 工具网格文字的原因——后文的 shader 缓存正是为此类成本准备的。二、Player 导出与 Shader 缓存2.1 导出要求与工程可执行设置36:58→41:00图必须包进带纹理输出的 Symbol根层级不能有输出player 从该输出推导分辨率因此导出前要把图包装成带 texture 输出的 symbol。标题、作者、以及新的strip unused operators剔除未用操作符选项位于工程的 executable settings工程可执行设置中现在也可以从工程内部直接点导出按钮。剔除未用操作符还会把未连接的资产如视频挡在打包产物之外。2.2 Shader 缓存从一分钟编译到几秒启动41:00→44:05shader 变体按其代码字符串哈希、缓存到磁盘导出产物现在会携带该缓存把一个 demo 的启动时间从超过一分钟的 shader 编译降到几秒。仓库中的对应实现编译缓存核心在 Core/Resource/ShaderCompiling/ShaderCompiler.Caching.cs编译成功的字节码按ulong hash写盘SaveBytecodeToDisk见 L162-L166命中时走内存缓存或TryLoadBytecodeFromDiskL144导出时会把哈希对应的字节码文件写入目标目录File.WriteAllBytes(Path.Combine(targetDirectory, hash FileExtension), bytecode)L150即导出携带缓存player 端配置了独立的缓存根路径与随附的种子缓存目录Player/Program.cs 中设置ShaderCompiler.ShaderCacheRootPath、ShaderCacheSubdirectory与ShaderCacheSeedDirectoryL123-L125种子目录即发布包内置的编译产物。2.3 会话中顺带提到的编辑器/播放器行为粉色启动屏51:05→51:40粉色 splash 表示你在跑 alpha main 分支它使用独立的设置与工程目录不会触碰稳定版工程的文件。时间线音轨改为片段51:43→53:30配乐不再是单一背景轨可拖入音频或新建片段、裁剪、多轨堆叠波形/频谱显示可切换并带自动播放保证导出无需手动接线 player。导出可执行文件54:23→55:30命名使用工程标题启动对话框可选择输出屏幕并带加载画面取代旧版固定屏幕行为。全屏稳定性57:01→58:35过去 Alt-Tab 或 HDMI 切换器换端口会让独占全屏当场崩溃player 现在与编辑器一样使用窗口化全屏模式显示变化时存活。G 键自动布局58:42→1:01:10按 G 对选中图部分自动布局适合在间距宽松的区域上运行对紧密堆叠的图运行可能产生不可用的布局。顺带一提[DisplaceMeshVAT]1:16:33→1:16:55是被点名用于把带骨骼角色带进演示的顶点动画纹理路线等待真正的角色动画支持。三、文字描边粒子发射器3.1 粒子模型属性缓冲而非 over-lifetime 曲线1:27:21→1:29:15与 Unity 的 over-lifetime 曲线不同TiXL 中逐粒子的行为来自你自己映射的属性缓冲——而寿命lifetime恰恰是这个模型里最难上手的部分寿命0 时自动推导1:36:50→1:38:25寿命取最大数量 ÷ 发射速率当发射率变化或脉冲时它会静默改变应显式设置寿命——注意它的单位是bars小节实际时长依赖 BPM/帧率。阻尼1:47:46→1:48:35默认阻尼因子会在发射后逐渐刹车调低它粒子会沿初始发射方向继续滑行。3.2 用 [LineTextPoints] 生成发射路径1:29:24→1:32:20[LineTextPoints] 把字体描边生成为 GPU 线点是融化 Logo这类效果的理想发射路径粒子沿字母笔画出生。当前源码 Operators/Lib/Symbols/point/io/LineTextPoints.cs 展示了它的完整实现字体来自SVG 线字体文件FilePath输入内部用LineFont.Create解析svg:font字形表L429-L442含字距kerning表两个输出ResultList点列表与StartIndicesAndCountsL27后者记录每个字符的起始索引与点数便于按字符操作每个点都计算了朝向沿笔画方向见 L579-L625 的相邻点角度推导子路径以Point.Separator()分隔L34——点缓冲里 NaN 分隔符正是绘制操作符识别线段断点的通用约定如 DrawLines 的说明W 属性为 NaN 的点不绘制并作为相邻线段分隔符SetFx1To可把点 F1 写为字符/词/行序号Entities枚举L332-L341方便后续按实体做属性映射尺寸缩放按 1080p/72DPI 的 pt 字号对齐L131。该操作符源码注释指出这是一个折中方案并指向项目 wiki 的 SvgLineFonts 补充说明。配套示例见 Operators/examples/Symbols/lib/point/LineTextPointsExamples.cs。疏密控制1:32:40→1:34:00想要更稀或更密的描边可以用 [FilterPoints] 按起始索引过滤或用 [SubdivideLinePoints] 按步数细分每段线直到笔画分辨率满足发射需求。沿描边爬行的单点发射器1:34:00→1:35:10把 [ResampleLinePoints] 切到 startlength 模式且长度设为 0即精确采样一个点再动画化归一化的 start0..1 覆盖整段文字就能让一个发射点沿描边爬行用 Ctrl 把该参数拆出来break out再接 [AnimValue] 动画。出生行为1:35:10→1:36:15新发射的粒子会沿每个点的局部 Z 飞走默认发射速度为 1若希望粒子留在出生点把发射速度清零或调低。3.3 力、体积与属性映射[DirectionalForce]1:36:18→1:36:50最简洁的让粒子下落的力。寿命属性映射1:38:28→1:41:05本段 85% 置信度让粒子系统把归一化年龄写入 F1 属性再把 [MapPointAttributes] 的输入模式从 buffer-position 切到 F1就能用 F1 驱动一个梯度颜色和一条曲线缩放得到 Unity 风格的 over-lifetime 淡出/缩小且在寿命参数变化时依然成立。体积爆发1:41:17→1:43:10用 [SpherePoints] 每帧发射一整层球面点而非单点即可做出体积爆发再用 [PerlinNoise] 逐帧调制球半径流就变成毛球状形状。点的朝向1:43:20→1:44:15[VisualizePoints] 显示每个点的方向轴蓝色局部 Z球面与网格散射的点朝外指向类似法线直接决定粒子发射方向而 [GridPoints] 生成的点不这样。[RepeatAtPoints]1:44:20→1:46:00在每个目标点实例化一小团点云例如把一个发射球挂在沿文字描边爬行的单点之上爆发就跟着笔画走。[TurbulenceForce]1:46:02→1:46:40与重力并排即可让下落粒子立刻显得有生命[RandomizePoints]1:46:40→1:47:45给随机相位喂一个驱动值如时间散射每帧重新随机化静态偏移变成活跃喷溅。3.4 两个高价值 Gotcha寿命回绕1:55:05→1:58:35粒子在临死时刻莫名变亮时做最小复现把一个 Lissajous 式振荡的单点[OscillateVec3]接入系统可暴露年龄越过设定寿命后回绕而不是干净死亡的行为。NaN 死粒子必须跳过1:58:35→2:07:0085% 置信度死粒子仍留在固定大小的缓冲里靠 NaN 缩放标记绘制操作符会跳过它们任何对原始缓冲做映射的节点如 MapPointAttributes 类也必须跳过这些 NaN 条目——否则过期粒子会在梯度位置 0 处被重采样以完整尺寸和颜色复活。这与 DrawLines/DrawRibbons 文档中NaN 作为分隔/跳过的约定一致。3.5 视觉与音频调制发光色彩1:48:39→1:52:30把自发光色压在略低于全饱和让被裁掉的高强度通道向白渗读起来是灼热而非平涂纯色[ui:ColorEditor] 中的条纹区域标示超范围值[Glow] 之后接 [ToneMapping] 的 AGX 对过亮部分恢复效果很好。[AudioReaction] 输出模式1:52:45→1:55:05刻意选择输出模式——Threshold 命中是一次性爆炸触发按住 Ctrl 可拖阈值线Level 连续跟随响度AccumulatedLevel 持续增长适合驱动一个相位。三者都可调制发射速度或数量。外部触发播放3:38:22→3:41:10[PlayVideo] 由外部事件触发播放把 [StopWatch] 的经过秒数喂给视频的 time 输入用 [Trigger] 启停秒表关闭循环让片段在结尾停住。四、Anaglyph 立体相机管线4.1 双相机渲染结构2:09:55→2:23:30实时调参2:09:55→2:12:30场景把 [MouseInput] 位置映射到眼睛间距戴红绿眼镜时可直接现场调立体深度。为什么用两个偏移相机2:12:30→2:16:10抽出立体组件意味着把一台相机拆成被复用的引用但投影空间平移算子[ShiftCamera]无法产生所需的视空间眼睛偏移——当前源码印证了这一点Operators/Lib/Symbols/render/camera/ShiftCamera.cs 只修改context.CameraToClipSpace的 M31/M32/M33L32-L37即投影空间。因此该方案改用 [ReuseCamera] 两台偏移相机渲染ReuseCamera 从ICamera引用取出WorldToCamera与CameraToClipSpace临时替换进上下文再求值子树L32-L41。双次渲染的写法2:16:20→2:19:00用 [Loop] 迭代一个索引变量下游用 [GetFloatVar] 读取并翻转眼睛偏移符号场景因此渲染两遍。注意同一结构可能扰乱粒子系统——每次迭代都会重新求值子树示例见 Operators/examples/Symbols/lib/flow/LoopExample.cs。合成2:19:14→2:20:30每只眼的渲染通道各自染色红/青后用 [Layer2d] 作为 2D 层合成——所以场景确确实实每帧渲染两次。参数要点2:20:30→2:23:30立体眼距必须随场景尺寸反向缩放——小物体需要很大的眼距反之亦然额外的镜头平移项lens-shift作用在裁剪空间clip space里视觉上成立尽管数学并未完全验证。校准辅助2:25:03→2:25:45[CommonPointSets] 的预设如立方体随时可用作为判断深度或校准 3D 效果的即时参照物。Bloom 顺序2:28:00→2:28:20在合并立体通道之前对每只眼单独加 [Bloom]在红/青合成之后再加两只眼就会不一致。4.2 把立体管线符号化2:31:20→2:39:20打包成操作符2:31:20→2:34:30把整套立体管线组合成新的操作符类型[ui:Symbol]把调参值提升为输入参数右键 set as default 让当前工作值成为新操作符的默认值。设计上的理想形态是一台相机 视空间偏移节点 两个 RenderTarget——但现有 shift 算子只改投影空间见上文 ShiftCamera 源码。Obj 类型相机引用输入2:34:40→2:36:30给操作符加一个 Obj 类型的输入参数作为相机引用外部场景相机即可像后期特效算子一样被接进来驱动内部渲染。4.3 现场编码 [CamPosition] 的相机引用输入2:51:16→2:58:5585% 置信度原 [CamPosition] 只从评估上下文的当前相机读取位置与方向。会话现场完成了扩展四步复制一个现有输入定义给它一个全新的 GUID复用 ID 会让连接携带错误类型运行时无法重映射会把它们当成全新输入处理并丢失所有连接——见 3:22:20→3:24:30 关于改类型必须换 GUID 的告诫取引用相机的世界/裁剪矩阵而不是上下文相机的视线目标 位置 方向向量。值得注意当前仓库源码 Operators/Lib/Symbols/render/camera/CamPosition.cs 中已经带有CamReference输入L67-L68并在Update里优先使用引用相机的WorldToCamera/CameraToClipSpaceL43-L47再反求相机到世界矩阵得到Position、用pos - Transform(0,0,1,1)得到DirectionL50-L54——即会话中现场编码的能力已合入主线。配套示例见 Operators/examples/Symbols/lib/render/camera/CamPositionExample.cs。4.4 评估上下文的失效/缓存边界这一段的讨论对任何调试 TiXL 图的人都很有价值变量对渲染出旧值2:40:48→2:44:40当 SetFloatVar/GetFloatVar 对读到过期结果时打开 [Group] 的force-invalidate-childrenforce color update复选框让子树每次求值都重新变脏普通 [Execute] 算子没有这个选项而且该标志代价高昂——它会击穿其下所有缓存。失效机制原理2:45:19→2:48:1085% 置信度失效机制为每个输入保存帧号 更新周期的组合戳避免共享分支每帧被取两次像变量读取这种时间相关叶子必须把脏状态向上传播——force-invalidation 标志正是为子树重新触发这件事。[Loop] 的边界2:48:53→2:51:10每次迭代内部已经做了新帧脏标记跨迭代结果相同类 bug 多半另有原因建议收集最小复现——这类缓存边角问题最难排查。改完操作符看起来没反应3:00:00→3:01:20先检查 pin 住的输出——pin 错了别的操作符会让新加的相机输入看起来坏了而直接看代码其实是好的。调试库代码2:36:30→2:39:20修改库代码需要重启进入 debug 构建因为 release 模式锁定内置库。4.5 现场创建 [RemapVec3]3:15:33→3:26:40通过复制 Vec2 版本[RemapVec2]并把每个字段加宽到三分量[RemapVec3]现场造出bias-and-gain 整形被刻意丢弃它只作用于 0..1 无符号值对向量的每个分量施加没有意义收尾建议收紧默认值与 min/max 范围用命名参数组parameter groups归组相关输入让参数列表读起来干净3:24:30→3:26:40相关但独立的话题采样默认线性过滤8x8 贴图也能画出平滑结果且边缘可见回绕逐绘制器的 filter 选项目前只在部分操作符里存在3:03:08→3:15:30。跨切面方案上下文级 sampler 覆写被否掉了盲目推广的路线——它会悄悄破坏内部采样查找表梯度、曲线、噪声的算子因此此类覆写应限定在 draw 类算子并在管线更下游的子场景处重置上下文3:07:25→3:13:45。[DrawPoints]/[Layer2d] 的采样默认 clampwrap/mirror/border含边界色选择器是很少用但值得暴露的选项3:13:47→3:15:30。4.6 周边讨论数位板笔绘3:28:00→3:32:15用数位板在 Sketch 里画效果不好疑似 ImGui 层输入限制图本身的导航提供 alt-平移/缩放与中键画布缩放适合笔的工作流。笔压 API3:32:22→3:36:20期望的笔版 MouseInput把压感/倾角暴露为操作符输出所依赖的 API 是 Windows 专属项目有意避免这类平台绑定。五、物理空间输出管理看板规划中会议最后 30 多分钟3:54:53→4:31:20给出了output management的完整设计蓝图推翻首版原型的原因3:54:53→3:57:30第一版原型在自己的面板里重新实现了参数编辑新设计保持单一选择模型——点击看板上任何实体都在常规参数视图中编辑。物理缩放的画布3:57:33→4:00:0085% 置信度规划中的看板是一张按真实尺寸缩放的画布米制栅格拖入平面图与参考照片、描出投影面、赋予真实尺寸——这样 mockup、博物馆角落与舞台布局都保持真实世界比例。切片与同型映射4:00:00→4:01:15内容算子出现在看板上从中切出切片slice把每个切片同型映射homographic mapping到表面区域再把表面绑定到机器本地的输出——HDMI、[SpoutOutput] 或 [NdiOutput]。多机渲染4:01:16→4:02:40因为每个编辑都已经是小型 undo/redo 命令把这些命令流式传输到网络就是多机boygrouping渲染同一工程、且每机独立绑定的计划基础。看板即世界视图4:02:40→4:06:1085% 置信度展开的看板本身就是真实世界视图——把某个表面切到舞台输出会向那面墙初始化一台正交相机点或 2D 层就直接落到物理空间基于 OpenCV 的扫描还可以借助已知参照点校准真实投影机。输出发送器是真正的图算子4:13:20→4:17:40output sender 是真正的图算子而 slice 是看板本地实体两者都能通过参数视图中的选择来编辑把内容绑定与硬件绑定分离后场馆可以把整套输出配置做成一个拖放文件任何工程直接插进去。无限画布与分辨率回溯传播4:22:38→4:29:1085% 置信度看板是带真实原点与标尺的无限画布图片可作参考层或合成输出LED 控制器式打包把旋转/分割的面板打包进一帧怪异分辨率的画面每个输出切片的分辨率会沿算子链向回传播——把 720p 改成 4K 不需要手动改任何地方。遮罩与暂缓项4:29:24→4:31:20mask 规划为每切片的效果子段而非独立实体圆顶/软边投影刻意缓行——技术上可用手动重叠实现但在观察到真实使用模式之前不做专门工具。六、关键操作符速查主题操作符仓库位置SDF 文字混合BlendSDFWithSDF3 场输入 Range/OffsetOperators/Lib/Symbols/field/combine/BlendSDFWithSDF.cs2D 距离场Image2dSDFSdfImage/SdfScale/ImageSize/OffsetOperators/Lib/Symbols/field/generate/sdf/Image2dSDF.cs距离纹理生成JumpFloodFillImage/MaxIterationCountOperators/Lib/Symbols/image/generate/misc/JumpFloodFill.cs文字描边点LineTextPointsSVG 线字体 StartIndicesAndCountsOperators/Lib/Symbols/point/io/LineTextPoints.cs立体相机ReuseCamera / ShiftCamera仅投影空间/ CamPosition含 CamReferencecamera 目录Shader 缓存哈希式字节码缓存与导出Core/Resource/ShaderCompiling/ShaderCompiler.Caching.cs、Player/Program.cs结语这场 4 个半小时的社区会话把 TiXL 的三条主线拧在了一起距离场混合含 sdfBlendByMask 的精确/平滑切换实现、属性缓冲驱动的粒子编程模型寿命显式化、F1 归一化年龄映射、NaN 死粒子约定与评估上下文的失效/缓存语义组合脏戳、force-invalidation、变量向上传播。文档中提到的所有gotcha——高度图不是良构 SDF、JumpFloodFill 只有外侧距离、ShiftCamera 只改投影空间、改输入类型必须换 GUID——都能在当前仓库源码中找到对应证据而现场编码的 CamPosition 相机引用输入如今已带CamReference落在主线中说明社区会话与代码库之间是持续收敛的关系。完整时间轴与每条提及的置信度标注可回到 .help/references/video-analysis/CNvtNwG2Mls.md 查阅。【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表