)
Unity弹窗背景虚化效果实战5分钟搞定高斯模糊Shader在移动应用和游戏UI设计中弹窗背景虚化效果已经成为提升用户体验的标准配置。这种效果不仅能让用户注意力集中在当前弹窗内容上还能保持整体视觉连贯性。想象一下当用户点击某个按钮时背景内容优雅地模糊淡化弹窗内容如同浮在毛玻璃上一般清晰呈现——这种交互细节往往能大幅提升产品的专业感和品质感。传统实现方式通常采用半透明黑色遮罩但这种方式缺乏层次感。而高斯模糊效果则通过智能算法模拟真实光学特性让UI界面瞬间拥有景深效果。本文将带你从零开始实现这一效果无需复杂插件只需5分钟即可完成从Shader编写到实际应用的全过程。1. 高斯模糊原理与实现方案选择高斯模糊的核心算法并不复杂对图像中的每个像素取其周围像素的加权平均值权重分布符合高斯函数即正态分布曲线。这种处理方式能产生自然的模糊效果因为它在模糊时更重视中心像素的影响这与人类视觉系统的特性高度吻合。在Unity中实现高斯模糊主要有三种方案后处理方案通过Camera的OnRenderImage接口处理整个屏幕图像RenderTexture方案将需要模糊的内容渲染到中间纹理再进行处理UI专用方案针对UGUI系统优化的局部模糊处理对于弹窗背景这种特定场景UI专用方案在性能和效果上最为平衡。以下是三种方案的对比方案类型性能消耗适用场景实现复杂度后处理高全屏特效中等RenderTexture中特定物体模糊较高UI专用低UGUI元素简单提示移动端设备建议使用UI专用方案它能将模糊范围精确控制在弹窗背景区域避免不必要的性能开销。2. Shader核心代码解析让我们直接来看实现弹窗背景虚化的核心Shader代码。这个Shader采用双Pass渲染策略先水平模糊再垂直模糊最终组合成完整的高斯模糊效果。Shader UI/BackgroundBlur { Properties { _Size (Blur Size, Range(0, 10)) 2 [HideInInspector] _MainTex (Base (RGB), 2D) white {} } SubShader { Tags { QueueTransparent } // 水平模糊Pass Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float _Size; v2f vert (appdata v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { float2 texelSize 1.0 / _ScreenParams.xy * _Size; fixed4 sum fixed4(0,0,0,0); // 水平方向9个采样点的高斯模糊 sum tex2D(_MainTex, i.uv float2(-4.0 * texelSize.x, 0.0)) * 0.05; sum tex2D(_MainTex, i.uv float2(-3.0 * texelSize.x, 0.0)) * 0.09; sum tex2D(_MainTex, i.uv float2(-2.0 * texelSize.x, 0.0)) * 0.12; sum tex2D(_MainTex, i.uv float2(-1.0 * texelSize.x, 0.0)) * 0.15; sum tex2D(_MainTex, i.uv) * 0.18; sum tex2D(_MainTex, i.uv float2(1.0 * texelSize.x, 0.0)) * 0.15; sum tex2D(_MainTex, i.uv float2(2.0 * texelSize.x, 0.0)) * 0.12; sum tex2D(_MainTex, i.uv float2(3.0 * texelSize.x, 0.0)) * 0.09; sum tex2D(_MainTex, i.uv float2(4.0 * texelSize.x, 0.0)) * 0.05; return sum; } ENDCG } // 垂直模糊Pass Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc // 与水平Pass相同的结构体定义 fixed4 frag (v2f i) : SV_Target { float2 texelSize 1.0 / _ScreenParams.xy * _Size; fixed4 sum fixed4(0,0,0,0); // 垂直方向9个采样点的高斯模糊 sum tex2D(_MainTex, i.uv float2(0.0, -4.0 * texelSize.y)) * 0.05; sum tex2D(_MainTex, i.uv float2(0.0, -3.0 * texelSize.y)) * 0.09; sum tex2D(_MainTex, i.uv float2(0.0, -2.0 * texelSize.y)) * 0.12; sum tex2D(_MainTex, i.uv float2(0.0, -1.0 * texelSize.y)) * 0.15; sum tex2D(_MainTex, i.uv) * 0.18; sum tex2D(_MainTex, i.uv float2(0.0, 1.0 * texelSize.y)) * 0.15; sum tex2D(_MainTex, i.uv float2(0.0, 2.0 * texelSize.y)) * 0.12; sum tex2D(_MainTex, i.uv float2(0.0, 3.0 * texelSize.y)) * 0.09; sum tex2D(_MainTex, i.uv float2(0.0, 4.0 * texelSize.y)) * 0.05; return sum; } ENDCG } } }这段代码的关键点在于采用分离式高斯模糊算法先水平后垂直处理大幅减少计算量每个方向使用9个采样点权重分配符合高斯分布_Size参数控制模糊程度可根据需要动态调整使用_ScreenParams自动适配不同分辨率3. 完整实现步骤现在让我们将Shader应用到实际项目中。以下是详细的实现流程创建Shader和材质在Unity中新建Shader文件粘贴上面的代码创建新材质选择刚创建的Shader将材质命名为BackgroundBlurMaterial设置UI层级结构创建Canvas Panel作为弹窗背景在Panel下添加实际弹窗内容调整Panel的层级确保它覆盖在需要模糊的内容之上配置模糊背景为Panel添加Image组件将创建的材质赋给Image的Material属性调整Image颜色和透明度建议使用半透明黑色动态控制模糊强度// 控制模糊强度的脚本示例 using UnityEngine; using UnityEngine.UI; public class BlurController : MonoBehaviour { [Range(0, 10)] public float blurSize 2f; private Material blurMaterial; void Start() { Image image GetComponentImage(); blurMaterial image.material; } void Update() { blurMaterial.SetFloat(_Size, blurSize); } // 显示弹窗时调用 public void ShowDialog() { blurSize 5f; // 强模糊效果 gameObject.SetActive(true); } // 隐藏弹窗时调用 public void HideDialog() { gameObject.SetActive(false); } }性能优化技巧对于静态背景可以预先渲染模糊效果动态模糊时考虑降低采样点数在低端设备上提供关闭选项注意在Unity 2019及以上版本中可能需要启用Allow HDR和Enable Post-processing选项才能获得最佳效果。4. 进阶优化与平台适配为了让效果在各种设备上都能良好运行我们需要考虑一些优化策略移动端适配方案降低采样点数将9个采样点减少到5个使用更简单的权重分配添加设备性能检测自动调整模糊质量// 简化版移动端模糊Shader片段 sum tex2D(_MainTex, i.uv) * 0.4; sum tex2D(_MainTex, i.uv float2(1.0 * texelSize.x, 0.0)) * 0.2; sum tex2D(_MainTex, i.uv float2(-1.0 * texelSize.x, 0.0)) * 0.2; sum tex2D(_MainTex, i.uv float2(2.0 * texelSize.x, 0.0)) * 0.1; sum tex2D(_MainTex, i.uv float2(-2.0 * texelSize.x, 0.0)) * 0.1;动态模糊强度过渡添加平滑过渡效果让模糊程度可以随时间变化// 平滑过渡模糊强度 public float targetBlurSize 2f; public float blurTransitionSpeed 3f; void Update() { float currentSize blurMaterial.GetFloat(_Size); float newSize Mathf.Lerp(currentSize, targetBlurSize, Time.deltaTime * blurTransitionSpeed); blurMaterial.SetFloat(_Size, newSize); } public void SetBlurSize(float size) { targetBlurSize size; }多平台兼容性处理不同平台可能需要特殊处理平台注意事项解决方案iOS Metal可能不支持某些Shader语法使用标准CG语法Android OpenGLES2精度限制降低计算精度WebGL纹理采样限制减少采样次数在最近的一个商业项目中我们为弹窗系统实现了这种背景虚化效果。最初版本在高端设备上运行流畅但在中低端Android设备上出现了明显卡顿。通过引入动态质量调整机制根据设备GPU性能自动选择模糊质量等级最终在所有目标设备上都保持了60fps的流畅度。