原理
就是取自身以及該畫素周圍的8個畫素的顏色值相加,然後除9取個平均值,得到最終顏色值
效果
因為模糊後會出現一些方形的畫素效果,模糊效果不是很平均,所以均值模糊也叫做盒狀模糊。
c#程式碼
using UnityEngine; public class BoxBlurEff : MonoBehaviour { public Shader m_Shader; public Material m_Material; [Range(-3, 3)] public float m_BlurOffset = 1; void Start() { InitMaterial(); } private void InitMaterial() { if (false == SystemInfo.supportsImageEffects) { Debug.LogWarning("This platform does not support image effects or render textures."); this.enabled = false; return; } if (null == m_Material) { if (null != m_Shader && m_Shader.isSupported) { m_Material = new Material(m_Shader); m_Material.hideFlags = HideFlags.DontSave; } } else if (null != m_Shader && m_Material.shader != m_Shader) { if (m_Shader.isSupported) //優先shader { m_Material = new Material(m_Shader); m_Material.hideFlags = HideFlags.DontSave; } else { m_Material = null; } } if (null != m_Material) m_Material.SetFloat("_BlurOffset", m_BlurOffset); } private void ReleaseRT(RenderTexture rt) { if (rt != null) RenderTexture.ReleaseTemporary(rt); } private void OnRenderImage(RenderTexture source, RenderTexture destination) { if (null == m_Material) { Graphics.Blit(source, destination); } else { #if UNITY_EDITOR m_Material.SetFloat("_BlurOffset", m_BlurOffset); #endif Graphics.Blit(source, destination, m_Material, 0); } } }
shader
Shader "My/PostEff/BoxBlur" { CGINCLUDE #include "UnityCG.cginc" sampler2D _MainTex; float4 _MainTex_TexelSize; //貼圖大小資訊, 1/width, 1/height, width, height float _BlurOffset; fixed4 fragBoxBlur(v2f_img i) : SV_Target //片元著色器(逐畫素) { //均值模糊, 這邊沒有采樣9個, 只取樣了上下左右4個, 速度更快 float4 colBlur = 0; // (1/width, 1/height, -1/width, -1/height)*_BlueOffset float4 blurUV = _MainTex_TexelSize.xyxy * float4(1, 1, -1, -1) * _BlurOffset; //控制取樣上下左右1個畫素還是n個畫素 colBlur += tex2D(_MainTex, i.uv + blurUV.xy);//1,1 colBlur += tex2D(_MainTex, i.uv + blurUV.xw);//1,-1 colBlur += tex2D(_MainTex, i.uv + blurUV.zy);//-1,1 colBlur += tex2D(_MainTex, i.uv + blurUV.zw);//-1,-1 half4 col = tex2D(_MainTex, i.uv); //獲取畫素顏色 col.rgb = colBlur.rgb / 4; return col; } ENDCG Properties { _MainTex("Texture", 2D) = "white" {} //主貼圖 _BlurOffset("BlurOffset", Float) = 1 //模糊偏移 } SubShader { Cull Off //剔除關閉 ZWrite Off //寫入深度buff關閉 ZTest Always //深度測試開始 Pass //Pass0 { CGPROGRAM #pragma vertex vert_img #pragma fragment fragBoxBlur ENDCG } Pass //Pass1 { CGPROGRAM #pragma vertex vert_img #pragma fragment fragBoxBlur ENDCG } } }
雙重模糊
單次的均值模糊,其實效果並不是很好,這邊可以透過雙重模糊來最佳化模糊效果
原理:將圖片解析度降低1倍(降取樣),做一次模糊,再降1倍,做一次模糊;
然後再將解析度升1倍(升取樣),做一次模糊,再升1倍,做一次模糊。
using UnityEngine; public class BoxBlurEff : MonoBehaviour { public Shader m_Shader; public Material m_Material; [Range(-3, 3)] public float m_BlurOffset = 1; public bool m_DoubleBlur; private int m_SrcRTWidth; private int m_SrcRTHeight; private RenderTexture m_RTHalfSize; //一半大小 private RenderTexture m_RTQuarterSize; //1/4大小 void Start() { InitMaterial(); } private void InitMaterial() { if (false == SystemInfo.supportsImageEffects) { Debug.LogWarning("This platform does not support image effects or render textures."); this.enabled = false; return; } if (null == m_Material) { if (null != m_Shader && m_Shader.isSupported) { m_Material = new Material(m_Shader); m_Material.hideFlags = HideFlags.DontSave; } } else if (null != m_Shader && m_Material.shader != m_Shader) { if (m_Shader.isSupported) //優先shader { m_Material = new Material(m_Shader); m_Material.hideFlags = HideFlags.DontSave; } else { m_Material = null; } } if (null != m_Material) m_Material.SetFloat("_BlurOffset", m_BlurOffset); } private void ReleaseRT(RenderTexture rt) { if (rt != null) RenderTexture.ReleaseTemporary(rt); } private void OnRenderImage(RenderTexture source, RenderTexture destination) { if (null == m_Material) { Graphics.Blit(source, destination); } else { #if UNITY_EDITOR m_Material.SetFloat("_BlurOffset", m_BlurOffset); #endif if (m_DoubleBlur) DoubleBlur(source, destination); else Graphics.Blit(source, destination, m_Material, 0); } } private void DoubleBlur(RenderTexture source, RenderTexture destination) { if (m_SrcRTWidth != source.width || m_SrcRTHeight != source.height) { m_SrcRTWidth = source.width; m_SrcRTHeight = source.height; m_RTHalfSize = RenderTexture.GetTemporary((int)(m_SrcRTWidth * 0.5f), (int)(m_SrcRTHeight * 0.5f)); m_RTQuarterSize = RenderTexture.GetTemporary((int)(m_SrcRTWidth * 0.25f), (int)(m_SrcRTHeight * 0.25f)); } //降取樣 Graphics.Blit(source, m_RTHalfSize, m_Material, 0); Graphics.Blit(m_RTHalfSize, m_RTQuarterSize, m_Material, 1); //升取樣 Graphics.Blit(m_RTQuarterSize, m_RTHalfSize, m_Material, 0); Graphics.Blit(m_RTHalfSize, destination, m_Material, 1); } void OnDestroy() { if (null != m_RTHalfSize) { RenderTexture.ReleaseTemporary(m_RTHalfSize); RenderTexture.ReleaseTemporary(m_RTQuarterSize); m_RTHalfSize = null; m_RTQuarterSize = null; } } }
效果
參考
Unity自定義後處理——模糊效果_unity圖片模糊效果-CSDN部落格
UnityShader例項13:螢幕特效之均值模糊(Box Blur) - yjbjingcha - 部落格園 (cnblogs.com)