TiXL DirectionalBlur 运算符详解:方向模糊的参数体系与 GPU 着色器实现原理
【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3
DirectionalBlur 是 TiXL 图像处理库Lib.image.fx.blur中的一个 GPU 模糊运算符,用于沿任意角度方向对传入图像产生运动模糊效果。本文基于其官方文档,结合仓库中的 HLSL 着色器实现、运算符 C# 类 与 运算符定义文件,完整讲解全部 12 个输入参数的语义与默认值、FXTexture 双通道(R/G)控制协议,以及高斯加权对称采样的底层算法,读完即可在 TiXL 中熟练搭建方向模糊与"模糊版输入作为控制纹理"的进阶效果。
功能概述
DirectionalBlur沿一个方向角度模糊传入的图像(Blurs the incoming image along a directional angle),适合模拟摄像机运动、物体高速移动、速度线等动感效果。与同目录下的 Blur(各向同性模糊)不同,它的模糊方向由角度参数显式控制,且支持通过一张额外的"效果纹理"(FXTexture)在画面不同区域动态改写角度与强度。
它的独特能力在于:角度和强度都可以通过一张 FXTexture 逐像素覆盖,纹理的 R 通道代表角度(Angle),G 通道代表强度(Strength)。官方文档特别提示,使用一张"输入图像自身的模糊版本"作为效果纹理尤其有趣(Using an effects texture, especially one that is a blurred version of the input image, is particularly interesting),可以派生出类似边缘发丝光、区域变速模糊等视觉风格。
该运算符归属于 Lib.image.fx.blur 运算符家族,与 Bloom、Blur、FastBlur、Sharpen 并列,是整个库中少数支持"逐像素方向控制"的模糊工具。
输入参数详解
DirectionalBlur 共暴露 12 个输入槽(与 DirectionalBlur.cs 中声明的输入槽一一对应),下表汇总了文档中的参数清单,并补充了从 DirectionalBlur.t3 中提取的默认值与取值范围说明:
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| Image | Texture2D(必填) | null | 待模糊的输入图像 |
| Size | Single | 0.1 | 模糊位移总长度(以 UV 为单位),值越大拖尾越长 |
| Samples | Single | 16.0 | 单侧采样次数,决定拖尾的平滑度与细腻度 |
| Angle | Single | 0.0 | 基础模糊方向角,单位度(0° 为水平) |
| FxTextures | Texture2D | null(未连接) | 可选控制纹理:R 通道提供角度增量,G 通道提供强度倍率 |
| FxAngleFactor | Single | 1.0 | 控制纹理 R 通道对角度的缩放系数(0 表示禁用角度覆盖) |
| FxSizeFactor | Single | 0.0 | 控制纹理 G 通道对强度的缩放系数(0 表示禁用强度覆盖) |
| RefinementPass | Boolean | false | 是否启用细化通道(二次渲染,提升拖尾尾部细节) |
| RefinementSamples | Int32 | 6 | 细化通道的采样次数 |
| RefineSizeFactor | Single | 0.0 | 细化通道的尺寸因子,可缩小细化通道的模糊位移 |
| Wrap | TextureAddressMode | Clamp | 采样越界时的纹理寻址模式 |
| Resolution | Int2 | (0, 0) | 输出分辨率;设为 0 时自动跟随目标分辨率 |
注:
Image是 Required(必填)输入,其余参数均有默认值,直接连接一张纹理即可得到可用的方向模糊输出。
参数的核心作用
- Size 与 Samples 决定拖尾形态:在着色器中,二者相除得到单次采样步长
dir = dir * (strength / NumberOfSamples)。固定 Size 时,Samples 越大,每步位移越小、拖尾越连续平滑,但 GPU 开销线性增长(循环体执行 2×N 次纹理采样)。 - Angle 决定方向:
Angle以度为单位传入着色器后转换为弧度,并换算为(cos, sin)方向向量。FXTexture 未连接时(FxAngleFactor 默认 1.0,但 FxTexture 的 r 通道取 0),角度完全由Angle决定。 - FxAngleFactor / FxSizeFactor 是开关型系数:着色器中角度公式为
angle = (Angle + FxAngleFactor * fx.r * 360)。将FxAngleFactor设为 0 即彻底关闭纹理角度覆盖;同理strength = Size * (1 + FxSizeFactor * fx.g),FxSizeFactor = 0时强度覆盖不生效。FxAngleFactor默认即为 1.0,而FxSizeFactor默认 0.0,说明默认只开放角度覆盖。 - Wrap 控制边缘行为:模糊采样会读取当前位置前后多个像素,当采样点越出纹理边界时,由
TextureAddressMode(如 Clamp、Wrap)决定取边还是回绕,直接决定画面边缘处的拖尾是否"漏色"。默认 Clamp 在大多数画面中表现最稳。
输出
| 名称 | 类型 |
|---|---|
| TextureOutput | T3.Core.DataTypes.Texture2D |
唯一的输出槽在 DirectionalBlur.cs 中声明,输出与输入同尺寸的模糊结果纹理,可直接连入后续图像处理链或最终合成。
GPU 实现原理:从着色器看方向模糊算法
DirectionalBlur 的核心逻辑全部在单像素着色器 DirectionalBlur.hlsl 中完成,全部代码如下:
cbuffer ParamConstants : register(b0) { float Size; float NumberOfSamples; float Angle; float FxAngleFactor; float FxSizeFactor; } cbuffer Resolution : register(b2) { float TargetWidth; float TargetHeight; }高斯权重表
static const int WEIGHT_COUNT = 10; static const float Gauss[WEIGHT_COUNT] = { 0.93, 0.86, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1 };算法并非均匀加权平均,而是使用一张 10 级、从 0.93 递减到 0.1 的静态高斯权重表:越靠近采样起点(当前位置)的样本权重越大,越远处的样本权重越小。这使模糊结果保留中心细节、拖尾呈现平滑衰减,而不是生硬的"重影"。
角度与强度的逐像素计算
float4 fx = FxTexture.Sample(samLinear, uv); float angle = (Angle + FxAngleFactor * fx.r * 360)* 3.141578/180; float2 dir = float2(cos(angle), sin(angle) ); float strength = Size * (1 + FxSizeFactor * fx.g); dir *= strength / NumberOfSamples; dir.y *= aspectRatio;- 用当前像素的 UV 采样
FxTexture:R 通道经FxAngleFactor放大 360 倍后叠加到Angle上(即 R=1.0 时等效增加整整一圈 360°),再换算为弧度; strength由Size与FxSizeFactor * fx.g共同决定;- 单位方向向量乘以
strength / NumberOfSamples得到单次采样步长; dir.y *= aspectRatio(宽高比修正)是保证方向角视觉正确性的关键一步:由于 UV 坐标系下像素并非正方形,若不修正 y 分量,斜向模糊会因宽高比失真而偏离设定的角度。这是从源码中可以明确看到的一个重要实现细节。
对称高斯采样循环
float2 pos = dir; float4 c = InputTexture.Sample(samLinear, input.texCoord); float totalWeight = 1; for (int i = 0; i < NumberOfSamples; ++i) { float index = (float)i*(WEIGHT_COUNT - 1)/NumberOfSamples; float weight = lerp(Gauss[(int)index], Gauss[(int)index + 1], frac(index)); c += InputTexture.Sample(samLinear, input.texCoord + pos)*weight; c += InputTexture.Sample(samLinear, input.texCoord - pos)*weight; pos += dir; totalWeight += 2*weight; } c.rgb = c/totalWeight; c.a = clamp(c.a/totalWeight, 0,1); return clamp(c,0,1000);- 循环沿方向向量逐级外推采样位置,对
+pos与-pos双向对称采样(一次循环两次采样),这就是为什么"拖尾"会同时向角度正反两个方向延伸,构成以原像素为中心的直线模糊; - 权重通过对高斯表相邻两项做
lerp插值获得,使Samples可以与固定长度的权重表(10 级)解耦,任意采样数都能得到平滑的权重曲线; - 中心像素权重恒为 1,两侧权重以
totalWeight += 2*weight累加,最终 RGB 与 Alpha 都除以总权重完成归一化,保证模糊前后整体亮度一致,最后clamp(c, 0, 1000)防止 HDR 数值溢出。
内部结构:主通道与细化通道
从 DirectionalBlur.t3 的连接图可以推断出该运算符内部由两个_multiImageFxSetup渲染通道组成:一个主模糊通道,一个由RefinementPass控制的细化通道,二者输出通过PickTexture选择。
- RefinementPass = false(默认):仅执行主通道,使用
Size、Samples、Angle等参数直接渲染; - RefinementPass = true:启用细化通道,以独立的
RefinementSamples(默认 6)与RefineSizeFactor进行二次渲染,用于增强拖尾尾部的细节层次; BoolToInt将布尔开关转为选择值驱动PickTexture,内部还包含Div(Size / Samples换算步长)、Multiply(细化尺寸因子缩放)等运算节点,以及一个加载Lib:images/basic/black-pixel.png的LoadImage作为UseFallbackTexture的回退纹理——当 FxTextures 未连接时,用黑色像素纹理保证着色器采样不会读空。
这种"一个运算符 = 一组内部算子图 + 一段 HLSL"的组合模式,是 TiXL 运算符库的通用组织方式:外层的 .t3 图负责参数路由与通道调度,真正的像素运算全部交给 GPU 着色器。
实战建议:把输入图像的模糊版当控制纹理
官方文档特别推荐了 FxTextures 的一种玩法:先对输入图像做一次模糊,再把模糊结果作为 FxTextures 输入。其效果逻辑在源码中清晰可见:
- 模糊后的纹理天然"抹平"了高频细节,其 R 通道在亮区/暗区之间呈现平滑过渡,作为角度源可以让模糊方向沿图像亮度梯度渐变,形成类似"沿轮廓方向流动"的质感;
- G 通道携带区域亮度信息,配合
FxSizeFactor可以让高亮区域拖尾更长、暗部几乎不动,实现局部变速模糊。
建议的参数起点:Size0.05~0.2,Samples8~32(实时场景取低值),FxAngleFactor1.0,FxSizeFactor0.5~2.0,Wrap保持 Clamp。若追求拖尾更柔和的边缘,可开启RefinementPass并保持RefinementSamples在 4~8 之间,注意细化通道会增加一整个全屏 Pass 的 GPU 开销。
相关资源
- DirectionalBlur 官方文档(本文关联文档)
- Lib.image.fx.blur 运算符目录
- DirectionalBlur.hlsl 着色器源码
- DirectionalBlur.cs 运算符类
- DirectionalBlur.t3 运算符定义与默认值
- 同级对比:非方向性的 Blur 与更快、仅提供半径控制的 FastBlur
【免费下载链接】t3TiXL is an open source software to create realtime motion graphics.项目地址: https://gitcode.com/GitHub_Trending/t3/t3
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考