.NiceMapMarker{width:100%;height:300px}@media (min-width: 1024px) {.NiceMapMarker{height:450px}}前言两段思路：5×5 固定核的“直接采样 + 权重相加”的高斯近似。“只保留 UV 不取颜色”的尝试。关键澄清：模糊的本质是对“颜色场（或其他可平均的场）做加权平均”。如果“只返回 UV 偏移”，实际上只是移动取样位置，不会产生模糊，而是错位/拉伸/畸变。想要真正的模糊，必须基于偏移后的 UV 去采样场景颜色（或已渲染的中间贴图），并做加权累加与归一化。结论：把“只要 UV”的想法改成“偏移 UV 后采样颜色并加权”，才是正确的屏幕模糊路径。基本是跟着kodeco中的教程中引发的思考。2. 屏幕空间采样的关键知识采样源：通常选择上一阶段的场景颜色（PostProcessInput0 / SceneColor）。在 Custom 节点中可使用 GetDefaultSceneTextureUV(...) 获取稳定的屏幕 UV，再用 SceneTextureLookup(...) 或 Texture2DSample(...) 取色。像素尺寸/步长（Texel Size）：用 GetPostProcessInputSize(0).zw 得到 (1/Width, 1/Height)，把“像素偏移”换成 UV 偏移。材质域与混合位置：Post Process 材质域；Blendable Location 选 Before 或 After Tonemapping 会影响观感与稳定性。经验上 After Tonemapping 在多数项目里更稳、更省，Before 可避免某些 TAA/GBuffer 交互问题。越界处理：大半径时请 saturate(uv) 或按需求改为镜像/包裹以避免边缘黑边。3. 三类核心实现（分离高斯 / Kawase / 径向模糊）3.1 分离高斯（Separable Gaussian）把 N×N 的核拆成 水平 N 次 + 垂直 N 次，采样数从 N² 降到 2N。常与下采样金字塔（1/2、1/4 分辨率）配合：在低分辨率上模糊、再回读插值，更干净、更省算力。适用：全屏柔和景深感、UI 背景虚化、过场淡入淡出背景。 优点：质量稳定，易控半径；配金字塔后性价比高。 缺点：需要两 Pass（或两次 Custom），管线稍复杂。3.2 Kawase / Dual Filter迭代式模糊：每一轮使用较小偏移，以多次 Pass 累积朦胧感。适用：追求更低成本、风格化的虚化。 优点：实现简单，开销小。 缺点：频响与高斯不同，边缘特性略“油”。3.3 径向模糊（Radial Blur）从某个中心（屏幕中心或自定义点）向外沿射线多次采样并平均，营造速度感/眩晕/开镜外圈虚化。要点：center、steps、strength 控制视觉；大半径/小步数易噪，配下采样/双线性可显著改善。4. 抗噪与稳定性：从“颗粒感/闪烁”到丝滑采样不足 + 步长过大 → 增加 taps / 减小 step；或采用分离高斯 + 下采样金字塔。点采样导致颗粒 → 在自定义 HLSL 中显式使用双线性采样器（示例里用 BilinearTextureSampler0）。TAA/DLSS 交互 → 尝试切换到 After Tonemapping，或在 Pass 顺序上做调整。越界采样 → saturate(uv)；或自定义镜像/包裹。单 Pass 大核 → 不建议。改为分离 + 金字塔或采用迭代式方案（Kawase/Dual）。大半径需求 → 从较低 LOD读取（Texture2DSampleLevel）可明显降噪。5. 可复制 HLSL 模板（Custom 节点）说明：以下代码用于Post Process 材质域的 Custom 节点。建议在材质中放一个 “SceneTexture: PostProcessInput0” 作为哑输入，以确保资源绑定；某些版本差异下，若宏或采样器名与工程不一致，请按照注释切换到另一种写法。5.1 直接 5×5 高斯（演示/小半径）// 输入：BlurRadius（建议 2~4），Range（像素步长） float2 uv = GetDefaultSceneTextureUV(Parameters, 14); float2 px = GetPostProcessInputSize(0).zw; // (1/Width, 1/Height) static const float kernel[25] = { 0.01, 0.02, 0.04, 0.02, 0.01, 0.02, 0.04, 0.08, 0.04, 0.02, 0.04, 0.08, 0.16, 0.08, 0.04, 0.02, 0.04, 0.08, 0.04, 0.02, 0.01, 0.02, 0.04, 0.02, 0.01 }; float stepPix = Range; // 以“像素”为单位的步长 float2 stepUV = px * stepPix; float3 sum = 0; int idx = 0; [unroll] for (int y = -2; y <= 2; ++y) { [unroll] for (int x = -2; x <= 2; ++x) { float2 o = float2(x, y) * stepUV; float3 c = Texture2DSample(PostprocessInput0, BilinearTextureSampler0, saturate(uv + o)).rgb; sum += c * kernel[idx++]; } } return float4(sum, 1);注：BilinearTextureSampler0 若在你版本中不可用，改用 SceneTextureLookup(saturate(uv + o), 14, /*Filtered=*/true).rgb 也可（不同版本宏名略有差异）。这里我尝试了不同的SceneTextureLookup，有一个感觉很像热成像，挺有意思的5.2 分离高斯 · 水平 Pass// Inputs: Radius (像素半径), Sigma (标准差) float2 uv = GetDefaultSceneTextureUV(Parameters, 14); float2 px = GetPostProcessInputSize(0).zw; float r = max(1.0, Radius); float sigma = max(0.001, Sigma); int K = (int)r; float wsum = 0; float3 sum = 0; [loop] for (int i = -K; i <= K; ++i) { float w = exp(-0.5 * (i*i) / (sigma*sigma)); float2 o = float2(i, 0) * px; float3 c = Texture2DSample(PostprocessInput0, BilinearTextureSampler0, saturate(uv + o)).rgb; sum += c * w; wsum += w; } return float4(sum / max(wsum, 1e-5), 1);5.3 分离高斯 · 垂直 Pass// 与水平 Pass 相同，把偏移从 (i, 0) 改为 (0, i) float2 uv = GetDefaultSceneTextureUV(Parameters, 14); float2 px = GetPostProcessInputSize(0).zw; float r = max(1.0, Radius); float sigma = max(0.001, Sigma); int K = (int)r; float wsum = 0; float3 sum = 0; [loop] for (int i = -K; i <= K; ++i) { float w = exp(-0.5 * (i*i) / (sigma*sigma)); float2 o = float2(0, i) * px; float3 c = Texture2DSample(PostprocessInput0, BilinearTextureSampler0, saturate(uv + o)).rgb; sum += c * w; wsum += w; } return float4(sum / max(wsum, 1e-5), 1);5.4 Kawase（双线性 + 迭代式）// Inputs: Iterations, OffsetPixels float2 uv = GetDefaultSceneTextureUV(Parameters, 14); float2 px = GetPostProcessInputSize(0).zw; int iters = max(1, (int)Iterations); float offPx = max(0.5, OffsetPixels); float3 col = Texture2DSample(PostprocessInput0, BilinearTextureSampler0, uv).rgb; [loop] for (int i = 0; i < iters; ++i) { float2 o = px * (offPx + i * 0.5); float3 s0 = Texture2DSample(PostprocessInput0, BilinearTextureSampler0, saturate(uv + float2( o.x, o.y))).rgb; float3 s1 = Texture2DSample(PostprocessInput0, BilinearTextureSampler0, saturate(uv + float2(-o.x, o.y))).rgb; float3 s2 = Texture2DSample(PostprocessInput0, BilinearTextureSampler0, saturate(uv + float2( o.x, -o.y))).rgb; float3 s3 = Texture2DSample(PostprocessInput0, BilinearTextureSampler0, saturate(uv + float2(-o.x, -o.y))).rgb; col = (col + s0 + s1 + s2 + s3) * 0.2; // 简单平均，可加权 } return float4(col, 1);5.5 径向模糊（Radial Blur）// Inputs: Center(float2, 0~1), Steps, Strength(0~1) float2 uv = GetDefaultSceneTextureUV(Parameters, 14); float2 center = Center; int steps = max(1, (int)Steps); float strength = Strength; float3 acc = 0; float wsum = 0; [loop] for (int i = 1; i <= steps; ++i) { float t = i / (float)steps; float2 suv = lerp(uv, center, t * strength); float w = 1; // 可换成 t 或其他分布权重 float3 c = Texture2DSample(PostprocessInput0, BilinearTextureSampler0, saturate(suv)).rgb; acc += c * w; wsum += w; } return float4(acc / max(wsum, 1e-5), 1);5.6 大半径降噪：低 LOD 预滤再细采样// Inputs: BaseLOD(>=0), FineRadius, FineWeight(0~1) float2 uv = GetDefaultSceneTextureUV(Parameters, 14); float2 px = GetPostProcessInputSize(0).zw; float baseLod = max(0, BaseLOD); float3 baseColor = Texture2DSampleLevel(PostprocessInput0, BilinearTextureSampler0, uv, baseLod).rgb; int K = (int)FineRadius; float3 sum = 0; float wsum = 0; [loop] for (int i = -K; i <= K; ++i) { float w = 1.0 / (1 + abs(i)); float2 o = float2(i, 0) * px * 2; // 少量细采样（水平为例） float3 c = Texture2DSampleLevel(PostprocessInput0, BilinearTextureSampler0, saturate(uv + o), baseLod).rgb; sum += c * w; wsum += w; } float3 fine = sum / max(wsum, 1e-5); float3 outc = lerp(baseColor, fine, FineWeight); return float4(outc, 1);降噪还是必要的，不降噪可能是这样的：6. 性能与平台注意事项分离高斯 vs 单次 NxN：分离将采样数从 N² → 2N；半径稍大时必须拆。下采样金字塔：在 1/2、1/4 分辨率上模糊，最后回读插值，更干净且更省。过滤与采样器：显式双线性采样（或各平台可用的等效过滤）能显著降噪。移动端：部分移动路径对 SceneTexture 支持有限，必要时改用自定义 RT 与自定义 Pass。版本差异：若 SceneTextureLookup 或 GetPostProcessInputSize 等接口报错，优先用材质节点 SceneTexture: PostProcessInput0 验证数据，再替换为 Custom。7. 在 EUW/蓝图中做成可调控的工具面板目标：一键用的“屏幕模糊控制面板”。在模糊材质中暴露参数：Radius/Sigma、Iterations/OffsetPixels（Kawase）、Center/Steps/Strength（径向）、BaseLOD/FineRadius/FineWeight。创建 MIC。在 EUW 做一个 UMG 面板：获取当前关卡的后处理体或相机的 Blendables。列表展示所有模糊 MIC，提供启用/禁用切换。滑条：半径、强度、步数、LOD；Center 支持“点击视口取点”。下拉：Blendable Location（Before/After Tonemapping）。预设按钮：UI 虚化 / 冲刺速度感 / 过场淡化，一键写入一组参数。补充：若项目用 Modular PP Pipeline，可把模糊打成独立 Pass（含 Downsample/Upsample），EUW 仅切换与参数化。8. 调试与排错清单在屏幕上叠加调试环/棋盘，检查半径与扩散是否均匀。大半径却颗粒 → 增加采样、启用双线性、从低 LOD 取样、或改走金字塔。出现闪烁/抖动 → 检查与 TAA/DLSS 的交互，尝试 After Tonemapping。边缘黑边 → saturate(uv) 或镜像/包裹。材质不生效 → 材质域是否为 Post Process；是否已把材质加入 Volume/Camera 的 Blendables；是否有哑 SceneTexture 节点启用宏。9. 附录：节点版（无自定义 HLSL）实现思路分离高斯（节点）：SceneTexture: PostProcessInput0 → 多个 TextureSample（设置 Bilinear）。uv + ±(px, 0)、uv + ±(0, px) 等偏移 → Add/Multiply 组合。用 ScalarParameter 控制半径/步长，AppendVector 组织偏移；最后 Weighted Add 并除以权重和。Kawase（节点）：小偏移四点取样（↗ ↖ ↘ ↙）求平均。多次迭代：串 N 个 MaterialFunction 或 Custom 包装的节点函数。径向模糊（节点）：计算方向 dir = normalize(center - uv)。多个 uv + t*dir*strength 的采样点累加平均。若需要进一步模板化，可把上述组合封装为 Material Function（MF），并提供 MF_RadialBlur, MF_GaussianSeparableH/V, MF_KawaseIter 等，统一参数命名。还有一个奇怪的彩蛋..