-FxYaM- - HLSL
type: channel
link: https://www.fxyam.cn/tag/HLSL/
items: 【UE】【HLSL】屏幕模糊-hlsl编写初体验

【UE】【HLSL】屏幕模糊-hlsl编写初体验
type: item
date: 2025-10-24T01:00:30+08:00
description: .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.0…