Unity Shader 学习笔记(21) 模糊、高斯模糊

44 篇文章 5 订阅
36 篇文章 5 订阅

Unity Shader 学习笔记(21) 模糊、高斯模糊

参考书籍:《Unity Shader 入门精要》
GaussianBlur类源码:GaussianBlur.cs


模糊

  • 均值模糊:卷积核各个元素都相等,且相加为1。即卷积后得到像素值是邻域内各像素平均值。
  • 中值模糊:即邻域内所有像素排序后中间那个,替换掉原颜色。
  • 高斯模糊:使用卷积核称作高斯核,高斯核是正方形的滤波核。

高斯模糊

高斯方程如下。σ为标准方差(一般为1)。即离得越近,影响越大,越模糊。
在这里插入图片描述

对应类似如下图的正态分布:
在这里插入图片描述

因为高斯核是正态分布的,所以可以简化高斯核:
在这里插入图片描述

迭代次数逐渐提高,每次迭代模糊采样跨度扩大,性能消耗增加:
在这里插入图片描述

迭代次数不变下(一次),提高模糊采样跨度:
在这里插入图片描述

减小屏幕获取纹理大小,性能消耗减小,可能会像素化:
在这里插入图片描述

GaussianBlur类(省略其他两个版本,可见最上方源码):

public class GaussianBlur : PostEffectsBase
{
    [Range(0, 4)]
    public int iterations = 3;                  // 模糊迭代次数
    [Range(0.2f, 3.0f)]
    public float blurSpread = 0.6f;             // 模糊范围,过大会造成虚影
    [Range(1, 8)]
    public int downSample = 2;                  // 减少采样倍数的平方。越大,处理像素越少,过大可能会像素化

    void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (TargetMaterial != null)
        {
	        int rtW = src.width / downSample;
	        int rtH = src.height / downSample;
	
	        RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);
	        RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
	        buffer0.filterMode = FilterMode.Bilinear;
	        Graphics.Blit(src, buffer0);                            // 用到所有Pass块
	
	        // buffer0 存将要被处理的缓存,buffer1存搞好的
	        for (int i = 0; i < iterations; i++)
	        {
	            material.SetFloat("_BlurSize", 1.0f + (i + 1) * blurSpread);
	
	            Graphics.Blit(buffer0, buffer1, material, 0);
	            Graphics.Blit(buffer1, buffer0, material, 1);
	        }
	
	        Graphics.Blit(buffer0, dest);
	        RenderTexture.ReleaseTemporary(buffer0);
	        RenderTexture.ReleaseTemporary(buffer1);
        }
        else
            Graphics.Blit(src, dest);
    }
}

Shader:

Properties {
	_MainTex ("Base (RGB)", 2D) = "white" {}
	_BlurSize ("Blur Size", Float) = 1.0		// 模糊采样距离,过大会产生虚影
}
SubShader {
	// 类似C++头文件功能。使用时不用包含在Pass块,Pass中直接指定顶点和片元着色器,可避免编写两个一样的frag函数
	CGINCLUDE

	...

	struct v2f {
		float4 pos : SV_POSITION;
		half2 uv[5]: TEXCOORD0;
	};
	  
	// appdata_img定义在UnityCG.cginc
	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) {
		... // 类似处理垂直模糊的顶点着色器
	}
	
	// 两个Pass公用片元着色器
	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"			// 定义名字。可以从其他Shader直接来使用该Pass
		
		CGPROGRAM
		  
		#pragma vertex vertBlurVertical  
		#pragma fragment fragBlur
		  
		ENDCG  
	}
	
	Pass {  
		NAME "GAUSSIAN_BLUR_HORIZONTAL"
		
		CGPROGRAM  
		
		#pragma vertex vertBlurHorizontal  
		#pragma fragment fragBlur
		
		ENDCG
	}
} 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值