Unity shade高斯模糊的实现

实现思路

模糊效果分为很多类型,如均值模糊,高斯模糊等等,模糊效果的实现都是对每一个像素,取它附近的一些像素,进行一些平均化的操作。因此每个像素和附近像素的差异就变小了,整个图也就变模糊了。
高斯模糊的做法是用二维正态分布,来计算每个每个像素应该占用的权值。而二维正态分布可以分成两个一维正态分布来计算。

代码实现

按思路实现即可,我们这里取横竖各五个像素来计算高斯模糊,当然也可以取更多的像素,只要根据正态分布函数计算出对应权值即可。
因为正态分布是一个偶函数所以我们这里也只用声明半边的权值。注意这里权值的总和需要为1
在片元着色器中依次遍历每个像素,获取rgb之后乘上权值就可以了,最后得到一个模糊化的像素返回。

fixed4 frag(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 index = 1; index < 3; index++)
            {
                sum += tex2D(_MainTex, i.uv[index]).rgb * weight[index];
                sum += tex2D(_MainTex, i.uv[index+2]).rgb * weight[index];
            }

            return fixed4(sum, 1);
        }

当然因为片元着色器中用到了5个像素的uv坐标,我们这里在顶点着色器中传入。
横竖分别要五个坐标,我们这里写了两个pass,一个是横向模糊,一个是竖向模糊。

 v2f vertV(appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            const half2 uv = v.uv;
            o.uv[0] = uv;
            o.uv[1] = uv + float2(0, _MainTex_TexelSize.y * 1);
            o.uv[2] = uv + float2(0, _MainTex_TexelSize.y * 2);
            o.uv[3] = uv + float2(0, _MainTex_TexelSize.y * -1);
            o.uv[4] = uv + float2(0, _MainTex_TexelSize.y * -2);
            return o;
        }

        v2f vertH(appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            const half2 uv = v.uv;
            o.uv[0] = uv;
            o.uv[1] = uv + float2(0, _MainTex_TexelSize.x * 1);
            o.uv[2] = uv + float2(0, _MainTex_TexelSize.x * 2);
            o.uv[3] = uv + float2(0, _MainTex_TexelSize.x * -1);
            o.uv[4] = uv + float2(0, _MainTex_TexelSize.x * -2);
            return o;
        }

在c#脚本中还可以声明一个迭代次数的变量,根据迭代次数来多次调用该shader进行多次高斯模糊,可以得到更加模糊的效果。

public class GaussianBlur : MonoBehaviour
{
    public Shader shader;
    public int iterationTime;

    private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        Material material = new Material(shader);
        var buffer=RenderTexture.GetTemporary(src.width, src.height);
        Graphics.Blit(src, buffer);
        for (int i = 0; i < iterationTime; i++)
        {
            var buffer2=RenderTexture.GetTemporary(src.width, src.height);
            Graphics.Blit(buffer, buffer2, material,0);
            RenderTexture.ReleaseTemporary(buffer);
            buffer = buffer2;
           
            
            buffer2=RenderTexture.GetTemporary(src.width, src.height);
            Graphics.Blit(buffer, buffer2, material,1);
            RenderTexture.ReleaseTemporary(buffer);
            buffer = buffer2;
        }
      
        Graphics.Blit(buffer, dest);
        RenderTexture.ReleaseTemporary(buffer);
    }
}

最后将c#脚本和shader挂在到同一个摄像机上,可以得到高斯模糊的效果如下。
在这里插入图片描述

完整代码

Shader "LX/GaussianBlur"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        ZTest Always
        Cull Off
        Zwrite Off

        CGINCLUDE
        #include "UnityCG.cginc"

        struct appdata
        {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
        };

        struct v2f
        {
            half2 uv[5]:TEXCOORD0;
            float4 vertex : SV_POSITION;
        };

        sampler2D _MainTex;
        float4 _MainTex_ST;
        half4 _MainTex_TexelSize;


        v2f vertV(appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            const half2 uv = v.uv;
            o.uv[0] = uv;
            o.uv[1] = uv + float2(0, _MainTex_TexelSize.y * 1);
            o.uv[2] = uv + float2(0, _MainTex_TexelSize.y * 2);
            o.uv[3] = uv + float2(0, _MainTex_TexelSize.y * -1);
            o.uv[4] = uv + float2(0, _MainTex_TexelSize.y * -2);
            return o;
        }

        v2f vertH(appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            const half2 uv = v.uv;
            o.uv[0] = uv;
            o.uv[1] = uv + float2(0, _MainTex_TexelSize.x * 1);
            o.uv[2] = uv + float2(0, _MainTex_TexelSize.x * 2);
            o.uv[3] = uv + float2(0, _MainTex_TexelSize.x * -1);
            o.uv[4] = uv + float2(0, _MainTex_TexelSize.x * -2);
            return o;
        }

        fixed4 frag(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 index = 1; index < 3; index++)
            {
                sum += tex2D(_MainTex, i.uv[index]).rgb * weight[index];
                sum += tex2D(_MainTex, i.uv[index+2]).rgb * weight[index];
            }

            return fixed4(sum, 1);
        }
        ENDCG
        Pass
        {
            NAME "G_V"
            CGPROGRAM
            #pragma vertex vertV
            #pragma fragment frag
            ENDCG
        }
        Pass
        {
            NAME "G_H"
            CGPROGRAM
            #pragma vertex vertH
            #pragma fragment frag
            ENDCG
        }


    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值