- 音视频
- 图形学
- 桌面应用
【免费下载链接】t3
TiXL is an open source software to create realtime motion graphics.
TiXL(实时动态图形创作工具)中的Lib.image.analyze.OpticalFlow是一个基于光流算法生成运动向量场(Motion Vector Field)的图像分析算子,其输出可直接驱动粒子系统,实现"视频内容牵引粒子流动"的实时视觉效果。本文将以 OpticalFlow 官方文档 为核心骨架,结合仓库内算子源码、HLSL 着色器实现与内置示例,系统讲解其原理、参数、数据编码方式与实战接线方法,帮助你快速上手并调出理想的运动跟随效果。
一、功能定位:从图像序列到运动向量场
光流(Optical Flow)描述的是相邻两帧图像之间像素的瞬时运动。OpticalFlow算子接收连续两帧图像作为输入,逐像素计算运动向量,并把结果编码进一张纹理输出:
- 红色通道(R):运动向量的 X 分量;
- 绿色通道(G):运动向量的 Y 分量;
- 蓝色通道(B):检测到的运动幅度(magnitude)。
这张"运动向量纹理"可以被其他算子采样:在粒子系统中读取对应位置的向量作为受力或速度方向,就能让粒子"顺着视频运动的方向"飘动,常用于烟雾、粒子拖尾、流动线条等实时视觉。官方文档明确其典型用途是"drive particle effects(驱动粒子效果)"。
二、核心算法:Lucas-Kanade 光流法
OpticalFlow的光流计算在像素着色器中实现,完整 HLSL 源码位于 Operators/Lib/Assets/shaders/img/fx/OpticalFlowKanade.hlsl,其文件头部注释表明该实现参考了 Shadertoy 上 mds2 的公开实现。
Lucas-Kanade 方法的基本假设是:在局部窗口内,光流近似恒定。着色器的计算流程如下:
- 亮度函数:
intensity()分别对两张输入纹理(inputTextureA、inputTextureB)做SampleLevel采样,取 RGB 三通道点积(1,1,1)得到灰度亮度,并以time参数做线性插值,用于计算时间差分。 - 7×7 邻域累积:着色器以当前像素为中心遍历 7×7 窗口,对每个邻域点计算:
It:时间方向亮度差(帧间变化);Ix、Iy:空间方向亮度梯度;- 累加构建结构张量
AtA(2×2 矩阵)与Atb(2 维向量)。
- 最小二乘求解:对
AtA求逆后与Atb相乘得到光流flow = AtA⁻¹ · Atb,并乘以固定系数0.1缩放。 - 数值保护:对结果为
NaN的分量强制置 0,避免平面/无纹理区域产生异常值。 - Clamp 归一化:利用
ClampRange参数把光流值夹取、平移并归一化到固定区间,再由Amount整体缩放。
从源码结构可以看到,着色器通过cbuffer ParamConstants接收Lod、Amount、ClampRange、OutputMode四个参数,与 C# 侧暴露的输入一一对应。
三、输入 / 输出一览
OpticalFlow的算子实例定义在 Operators/Lib/Symbols/image/analyze/OpticalFlow.cs,通过[Input]/[Output]特性声明了如下槽位:
| 名称 | 相关性 / 类型 | 说明 |
|---|---|---|
| Image | Texture2D(Required) | 当前帧图像 |
| Image2 | Texture2D(Required) | 上一帧图像 |
| Lod | Single | 采样输入纹理的 MipMap 层级,用于模糊光流结果 |
| VisualizeResult | Boolean | 是否输出"线条/棒状"可视化结果(见后文) |
| VisualizationScale | Single | 可视化结果的缩放比例 |
| Amount | Single | 控制检测到的运动幅度 |
| ClampRange | Vector2 | 对光流结果做钳制与归一化,防止数值过小或过大 |
| OutputMethod | Int32 | 输出方式:灰度(中性值 R 0.5, G 0.5, B 0)或带符号(范围 -1 到 1) |
输出:
| 名称 | 类型 |
|---|---|
| TextureOutput | T3.Core.DataTypes.Texture2D |
从 OpticalFlow.t3 的默认值定义可见,各参数初始值分别为:Lod = 0、VisualizationScale = 0、Amount = 1、OutputMethod = 0(Signed)、ClampRange = (0, 10)、VisualizeResult = false。其中OutputMethod在源码中映射为OutputModes枚举(Signed/GrayScale),因此界面上下拉框会显示这两个选项而非裸整数。
四、参数详解与调参建议
1. OutputMethod(输出方式)
- Signed(默认):直接输出带符号运动向量,范围为 -1 到 1,保留运动方向信息;
- GrayScale:输出"灰度"编码,中性值落在 R 0.5、G 0.5、B 0,适合需要把向量当作普通颜色贴图处理或喂给不支持负值的环节。
着色器中的对应逻辑为flow = OutputMode < 0.5 ? flow : saturate(flow + 0.5):Signed 模式直接透出,GrayScale 模式则将值整体平移 0.5 并饱和。
2. Amount(运动幅度)
对光流向量做整体缩放。数值越大,输出向量越长、运动响应越"夸张";数值越小,输出越"温和"。内置示例中一个用于粒子采样的OpticalFlow将Amount设为0.16,而另一个用于TextureMapForce受力贴图的实例设为0.29,可见针对不同下游用途需要单独调节该值。
3. Lod(MipMap 采样层级)
指定输入纹理采样的 MipMap 层级。层级越高,采样越模糊,等效于对光流结果做空间平滑,可以抑制细小噪声,代价是丢失高频运动细节。界面配置(OpticalFlow.t3ui)将该参数限定在 0 到 1 之间并启用了 Clamp,示例中的取值为0.24。
4. ClampRange(钳制与归一化范围)
一个 Vector2 参数,用于钳制并归一化光流结果,防止数值"过小不可见或过大溢出"。着色器实现为:先取绝对值方向、夹取到[ClampRange.x, ClampRange.y],减去下限、再除以区间宽度完成归一化,最后恢复符号。默认值为(0, 10)。当画面运动幅度较小时,可缩小 ClampRange 上限以放大有效信号。
五、为什么必须配合 KeepPreviousFrame
光流需要连续两帧图像才能计算运动,因此官方文档特别强调:序列帧可由 [KeepPreviousFrame] 算子生成。仓库中的 KeepPreviousFrame.cs 是一个基于双缓冲(Double Buffering)的实现:内部维护_prevTextureA/_prevTextureB两张纹理,每帧通过CopyResource把当前输入拷入缓冲区,并切换输出:
- CurrentFrame:当前帧;
- PreviousFrame:上一帧。
同时它会检测纹理描述(宽、高、格式、Mip 层级、采样数)是否变化,格式变化时自动重建缓冲区。标准接法是将KeepPreviousFrame.CurrentFrame接到OpticalFlow.Image,将PreviousFrame接到OpticalFlow.Image2。
六、可视化模式:把向量场画成线条
除了原始向量场,算子还内置了可视化能力:当VisualizeResult = true时,输出将切换为第二个着色器 OpticalFlowSticks.hlsl 的渲染结果。该着色器把画面划分为规则网格块(块大小由VisualizationScale与分辨率共同决定),在每个块中心按采样到的光流方向绘制短线("sticks"),实现"线条随运动方向排列"的流动感,并用dot(flow, flow)判断是否静止(静止区域输出圆形光点)。VisualizationScale用于控制线段的疏密/长度比例。
这一模式非常适合作为调试工具:在开发阶段开启可视化,直观确认向量方向是否正确、Amount 是否过冲,再关闭后接入粒子系统。
七、仓库内置示例:粒子系统实战
官方文档建议"Also check the example(参考示例)"。仓库中提供了完整的可运行示例 OpticalFlowExample.t3,其核心接线展示了典型工作流:
- PlayVideo播放视频(默认素材为
Examples:videos/spray-1080p.mp4),并循环输出帧; - 两个KeepPreviousFrame分别冻结前一帧,为光流提供两帧输入;
- 两个OpticalFlow实例并行计算运动向量场(分别驱动粒子属性和受力贴图);
- SamplePointSimAttributes对向量纹理按粒子位置采样(示例中 R 通道取 1、G 通道取 2、B 通道取 4 的通道映射,并配置
TextureScale、RedFactor、BlueFactor等)以驱动ParticleSystem粒子系统; - 另一路OpticalFlow输出连接TextureMapForce作为受力场;
- 最终粒子经过DrawPointsShaded/DrawLines/RepeatAtPoints等环节渲染输出,配合
_GridPoints_Old网格生成与TransformPoints旋转 90 度等辅助节点完成画面构图。
示例还演示了用HasIntChanged配合视频帧信号来控制Keep开关、用_Time_old驱动动画等细节,是理解"视频 → 光流 → 粒子"全链路的最佳参考。
八、调优实战小结
- 起步参数:保持
ClampRange默认(0,10)、Amount = 1与OutputMethod = Signed,先开启VisualizeResult观察向量方向是否正确; - 画面抖动明显:适当提高
Lod(如 0.2~0.5)平滑噪声; - 运动响应过强/过弱:调整
Amount,或收缩/扩大ClampRange区间来重新归一化; - 接入粒子前:确认采样算子的通道映射与向量纹理编码一致(RG 为方向、B 为幅度),避免出现粒子飞向错误方向的问题;
- 静止区域异常:Lucas-Kanade 在无纹理区域会得到近零矩阵,着色器已对
NaN做了保护,若仍有异常可依赖ClampRange收敛数值。
OpticalFlow是 TiXL 图像分析算子库 Lib.image.analyze 中连接"视频分析"与"粒子渲染"的关键一环,掌握其向量编码约定与参数语义,即可在实时场景中稳定复现"画面运动驱动粒子"的动态视觉效果。
- 音视频
- 图形学
- 桌面应用
【免费下载链接】t3
TiXL is an open source software to create realtime motion graphics.
相关推荐
TiXL 矢量场生成算子实战:用 ToroidalVortexField 打造环形涡旋粒子运动场
TiXL 矢量场生成算子实战:用 ToroidalVortexField 打造环形涡旋粒子运动场 TiXL(tooll3 的延续项目)在 Lib.field.g
音视频图形学桌面应用TiXL 的 ApplyVectorField 操作符完全指南:用矢量场驱动粒子朝向与属性
TiXL 的 ApplyVectorField 操作符完全指南:用矢量场驱动粒子朝向与属性 本文围绕 TiXL(实时动态图形创作工具)中 Lib.field.u
音视频图形学桌面应用TiXL 音频反应驱动动画实战:用 AudioReaction 让粒子场景跟着节拍律动
TiXL 音频反应驱动动画实战:用 AudioReaction 让粒子场景跟着节拍律动 本篇技术指南基于 Tooll 3 Tip 013 视频教程( M67r
音视频图形学桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考