原理
就是取自身以及该像素周围的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)
标签:模糊,RenderTexture,Material,均值,Shader,后处理,source,BlurOffset,null From: https://www.cnblogs.com/sailJs/p/18102055