Unity Shader 从未入门到已放弃(二十)--高级 高斯模糊

高斯滤波

高斯模糊使用了卷积计算,它使用的卷积核叫高斯核。高斯核的维数越高,模糊程度越大。

实现

首先创建cs脚本,利用两个临时缓存在迭代之间进行交替。

private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (material != null)
        {
            int rtW = source.width / downSample;
            int rtH = source.height / downSample;
            //分配一块小于屏幕大小的缓冲区 这样需要处理的像素就为几分之一 
            RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);
            buffer0.filterMode = FilterMode.Bilinear;

            Graphics.Blit(source, buffer0);

            for (int i = 0; i < iterations ; i++)
            {
                material.SetFloat("_BlurSize", 1.0f + i * blurSpread);

                RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);

                Graphics.Blit(buffer0, buffer1, material, 0);

                RenderTexture.ReleaseTemporary(buffer0);

                buffer0 = buffer1;
                buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);

                // Render the horizontal pass
                Graphics.Blit(buffer0, buffer1, material, 1);

                RenderTexture.ReleaseTemporary(buffer0);
                buffer0 = buffer1;
            }
            Graphics.Blit(buffer0, destination);
            RenderTexture.ReleaseTemporary(buffer0);

        }
        else
        {
            Graphics.Blit(source, destination);
        }
    }

首先定义一个缓存buffer0,并把source中的图像缩放后存到buffer0中。在迭代过程中定义了第二个缓存buffer1。在执行第一个Pass时,输入buffer0,输出buffer1,完毕后先把buffer0释放,再把buffer1存储到buffer0中,重新分配buffer1,再调pass2。迭代完后用Graphics.Blit(buffer0, destination)把结果显示到屏幕上。

shader内容:

SubShader
	{
		CGINCLUDE

		#include "UnityCG.cginc"  

		sampler2D _MainTex;
		half4 _MainTex_TexelSize;
		float _BlurSize;

		struct v2f {
			float4 pos : SV_POSITION;
			half2 uv[5]: TEXCOORD0; //5x5高斯核
		};

		v2f vertBlurVertical(appdata_img v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);

			half2 uv = v.texcoord;

			o.uv[0] = uv;
			o.uv[1] = uv + float2(0.0, _MainTex_TexelSize.y * 1.0) *_BlurSize;
			o.uv[2] = uv - float2(0.0, _MainTex_TexelSize.y * 1.0) *_BlurSize;
			o.uv[3] = uv + float2(0.0, _MainTex_TexelSize.y * 2.0) *_BlurSize;
			o.uv[4] = uv - float2(0.0, _MainTex_TexelSize.y * 2.0) *_BlurSize;

			return o;
		}

		v2f vertBlurHorizontal(appdata_img v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);

			half2 uv = v.texcoord;

			o.uv[0] = uv;
			o.uv[1] = uv + float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
			o.uv[2] = uv - float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
			o.uv[3] = uv + float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;
			o.uv[4] = uv - float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;

			return o;
		}

		fixed4 fragBlur(v2f i) :SV_Target{
			float weight[3] = {0.4026, 0.2442, 0.0545};
			
			fixed3 sum = tex2D(_MainTex, i.uv[0]).rgb * weight[0];

			for (int it = 1; it < 3; it++)
			{
				sum += tex2D(_MainTex, i.uv[it * 2 - 1]).rgb * weight[it];
				sum += tex2D(_MainTex, i.uv[it * 2]).rgb * weight[it];
			}

			return fixed4(sum, 1.0);
		}

		ENDCG
		
		ZTest Always Cull Off ZWrite Off

		Pass {
			NAME "GAUSSIAN_BLUR_VERTICAL"

			CGPROGRAM

			#pragma vertex vertBlurVertical  
			#pragma fragment fragBlur

			ENDCG
		}

		Pass{
			NAME "GAUSSIAN_BLUR_HORIZONTAL"

			CGPROGRAM

			#pragma vertex vertBlurHorizontal  
			#pragma fragment fragBlur

			ENDCG
		}
	}

使用CGINCLUDE避免我们写两个一样的frag函数。

 

效果图:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值