Unity Shader后处理中如何实现高斯模糊

发布时间:2022-01-05 15:15:54 作者:小新
来源:亿速云 阅读:236

Unity Shader后处理中如何实现高斯模糊

目录

  1. 引言
  2. 后处理概述
  3. 高斯模糊原理
  4. Unity中的后处理
  5. 实现高斯模糊的步骤
  6. 编写高斯模糊Shader
  7. 优化高斯模糊性能
  8. 实际应用案例
  9. 总结

引言

在游戏开发中,视觉效果是吸引玩家的重要因素之一。后处理技术作为提升游戏画面质量的重要手段,广泛应用于各种游戏中。高斯模糊作为一种常见的后处理效果,能够为游戏画面增添柔和、梦幻的氛围。本文将详细介绍如何在Unity Shader中实现高斯模糊效果。

后处理概述

后处理(Post-Processing)是指在渲染完场景后,对最终图像进行进一步处理的技术。通过后处理,开发者可以实现各种视觉效果,如模糊、色彩校正、景深、抗锯齿等。Unity提供了强大的后处理框架,使得开发者能够轻松实现各种复杂的视觉效果。

高斯模糊原理

高斯模糊是一种基于高斯函数的模糊算法,通过对图像中的每个像素进行加权平均来实现模糊效果。高斯函数具有钟形曲线的特点,中心像素的权重最大,随着距离的增加,权重逐渐减小。这种加权平均的方式能够有效地平滑图像,同时保留边缘信息。

高斯函数

高斯函数的数学表达式为:

[ G(x, y) = \frac{1}{2\pi\sigma^2} e^{-\frac{x^2 + y^2}{2\sigma^2}} ]

其中,( \sigma ) 是标准差,控制着模糊的程度。( \sigma ) 越大,模糊效果越明显。

卷积核

在实际应用中,高斯模糊通常通过卷积核(Kernel)来实现。卷积核是一个二维矩阵,矩阵中的每个元素对应高斯函数在相应位置的权重。通过对图像进行卷积操作,可以实现高斯模糊效果。

Unity中的后处理

Unity提供了多种方式来实现后处理效果,其中最常用的是通过编写自定义Shader和使用Unity的Post-Processing Stack。

自定义Shader

自定义Shader是Unity中最灵活的后处理实现方式。通过编写Shader代码,开发者可以完全控制后处理的每一个细节。本文将重点介绍如何通过自定义Shader实现高斯模糊效果。

Post-Processing Stack

Unity的Post-Processing Stack是一个功能强大的后处理框架,提供了多种内置的后处理效果,包括高斯模糊。通过简单的配置,开发者可以快速实现各种复杂的视觉效果。然而,Post-Processing Stack的灵活性相对较低,无法满足所有定制化需求。

实现高斯模糊的步骤

在Unity中实现高斯模糊效果,通常需要以下几个步骤:

  1. 创建后处理脚本:编写一个C#脚本,用于控制后处理的执行。
  2. 编写Shader:编写一个Shader,用于实现高斯模糊效果。
  3. 应用后处理:在场景中应用后处理效果,并调整参数以达到理想的效果。

创建后处理脚本

首先,我们需要创建一个C#脚本来控制后处理的执行。这个脚本需要继承自MonoBehaviour,并在OnRenderImage方法中调用Graphics.Blit方法,将后处理效果应用到渲染图像上。

using UnityEngine;

[ExecuteInEditMode]
public class GaussianBlur : MonoBehaviour
{
    public Material blurMaterial;

    void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (blurMaterial != null)
        {
            Graphics.Blit(src, dest, blurMaterial);
        }
        else
        {
            Graphics.Blit(src, dest);
        }
    }
}

编写Shader

接下来,我们需要编写一个Shader来实现高斯模糊效果。Shader的核心部分是通过卷积核进行图像处理。由于高斯模糊是二维的,我们需要分别在水平和垂直方向上进行模糊处理。

Shader "Custom/GaussianBlur"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _BlurSize ("Blur Size", Float) = 1.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float _BlurSize;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float2 texelSize = float2(1.0 / _ScreenParams.x, 1.0 / _ScreenParams.y);
                float2 uv = i.uv;

                fixed4 color = tex2D(_MainTex, uv) * 0.2270270270;
                color += tex2D(_MainTex, uv + float2(texelSize.x * 1.0, 0.0) * _BlurSize) * 0.1945945946;
                color += tex2D(_MainTex, uv - float2(texelSize.x * 1.0, 0.0) * _BlurSize) * 0.1945945946;
                color += tex2D(_MainTex, uv + float2(texelSize.x * 2.0, 0.0) * _BlurSize) * 0.1216216216;
                color += tex2D(_MainTex, uv - float2(texelSize.x * 2.0, 0.0) * _BlurSize) * 0.1216216216;
                color += tex2D(_MainTex, uv + float2(texelSize.x * 3.0, 0.0) * _BlurSize) * 0.0540540541;
                color += tex2D(_MainTex, uv - float2(texelSize.x * 3.0, 0.0) * _BlurSize) * 0.0540540541;

                return color;
            }
            ENDCG
        }
    }
}

应用后处理

最后,我们需要在场景中应用后处理效果。将编写好的后处理脚本挂载到相机上,并将Shader赋值给blurMaterial。通过调整_BlurSize参数,可以控制模糊的程度。

using UnityEngine;

public class ApplyGaussianBlur : MonoBehaviour
{
    public Material blurMaterial;
    public float blurSize = 1.0f;

    void Start()
    {
        GaussianBlur blur = gameObject.AddComponent<GaussianBlur>();
        blur.blurMaterial = blurMaterial;
        blurMaterial.SetFloat("_BlurSize", blurSize);
    }
}

编写高斯模糊Shader

在上一节中,我们已经编写了一个简单的高斯模糊Shader。然而,这个Shader只实现了水平方向的模糊。为了实现更高质量的模糊效果,我们需要在垂直方向上也进行模糊处理。

双Pass模糊

为了实现水平和垂直方向的模糊,我们可以使用双Pass的方式。第一个Pass用于水平方向的模糊,第二个Pass用于垂直方向的模糊。

Shader "Custom/GaussianBlur"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _BlurSize ("Blur Size", Float) = 1.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float _BlurSize;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float2 texelSize = float2(1.0 / _ScreenParams.x, 1.0 / _ScreenParams.y);
                float2 uv = i.uv;

                fixed4 color = tex2D(_MainTex, uv) * 0.2270270270;
                color += tex2D(_MainTex, uv + float2(texelSize.x * 1.0, 0.0) * _BlurSize) * 0.1945945946;
                color += tex2D(_MainTex, uv - float2(texelSize.x * 1.0, 0.0) * _BlurSize) * 0.1945945946;
                color += tex2D(_MainTex, uv + float2(texelSize.x * 2.0, 0.0) * _BlurSize) * 0.1216216216;
                color += tex2D(_MainTex, uv - float2(texelSize.x * 2.0, 0.0) * _BlurSize) * 0.1216216216;
                color += tex2D(_MainTex, uv + float2(texelSize.x * 3.0, 0.0) * _BlurSize) * 0.0540540541;
                color += tex2D(_MainTex, uv - float2(texelSize.x * 3.0, 0.0) * _BlurSize) * 0.0540540541;

                return color;
            }
            ENDCG
        }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float _BlurSize;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float2 texelSize = float2(1.0 / _ScreenParams.x, 1.0 / _ScreenParams.y);
                float2 uv = i.uv;

                fixed4 color = tex2D(_MainTex, uv) * 0.2270270270;
                color += tex2D(_MainTex, uv + float2(0.0, texelSize.y * 1.0) * _BlurSize) * 0.1945945946;
                color += tex2D(_MainTex, uv - float2(0.0, texelSize.y * 1.0) * _BlurSize) * 0.1945945946;
                color += tex2D(_MainTex, uv + float2(0.0, texelSize.y * 2.0) * _BlurSize) * 0.1216216216;
                color += tex2D(_MainTex, uv - float2(0.0, texelSize.y * 2.0) * _BlurSize) * 0.1216216216;
                color += tex2D(_MainTex, uv + float2(0.0, texelSize.y * 3.0) * _BlurSize) * 0.0540540541;
                color += tex2D(_MainTex, uv - float2(0.0, texelSize.y * 3.0) * _BlurSize) * 0.0540540541;

                return color;
            }
            ENDCG
        }
    }
}

双Pass模糊的应用

在应用双Pass模糊时,我们需要在C#脚本中分别调用两个Pass。通过使用中间RenderTexture,我们可以将第一个Pass的结果传递给第二个Pass。

using UnityEngine;

[ExecuteInEditMode]
public class GaussianBlur : MonoBehaviour
{
    public Material blurMaterial;
    public float blurSize = 1.0f;

    void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (blurMaterial != null)
        {
            RenderTexture temp = RenderTexture.GetTemporary(src.width, src.height);
            Graphics.Blit(src, temp, blurMaterial, 0);
            Graphics.Blit(temp, dest, blurMaterial, 1);
            RenderTexture.ReleaseTemporary(temp);
        }
        else
        {
            Graphics.Blit(src, dest);
        }
    }
}

优化高斯模糊性能

高斯模糊是一种计算密集型操作,尤其是在高分辨率下。为了提高性能,我们可以采用以下几种优化方法:

  1. 降低分辨率:通过降低渲染分辨率,可以减少计算量。在模糊效果不明显的情况下,这种方法非常有效。
  2. 分离模糊:将高斯模糊分解为水平和垂直两个方向的模糊,可以减少计算量。
  3. 使用降采样:通过降采样技术,可以在低分辨率下进行模糊处理,然后将结果上采样到高分辨率。

降低分辨率

降低分辨率是最简单的优化方法。通过将渲染目标的分辨率降低一半或更多,可以显著减少计算量。

using UnityEngine;

[ExecuteInEditMode]
public class GaussianBlur : MonoBehaviour
{
    public Material blurMaterial;
    public float blurSize = 1.0f;
    public int downSample = 2;

    void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (blurMaterial != null)
        {
            int width = src.width / downSample;
            int height = src.height / downSample;

            RenderTexture temp1 = RenderTexture.GetTemporary(width, height);
            RenderTexture temp2 = RenderTexture.GetTemporary(width, height);

            Graphics.Blit(src, temp1);

            Graphics.Blit(temp1, temp2, blurMaterial, 0);
            Graphics.Blit(temp2, temp1, blurMaterial, 1);

            Graphics.Blit(temp1, dest);

            RenderTexture.ReleaseTemporary(temp1);
            RenderTexture.ReleaseTemporary(temp2);
        }
        else
        {
            Graphics.Blit(src, dest);
        }
    }
}

分离模糊

分离模糊是将高斯模糊分解为水平和垂直两个方向的模糊。这种方法可以减少计算量,同时保持模糊效果。

”`csharp Shader “Custom/GaussianBlur” { Properties { _MainTex (“Texture”, 2D) = “white” {} _BlurSize (“Blur Size”, Float) = 1.0 } SubShader { Tags { “RenderType”=“Opaque” } LOD 200

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

        #include "UnityCG.cginc"

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

        struct v2f
        {
            float2 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
        };

        sampler2D _MainTex;
        float _BlurSize;

        v2f vert (appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            o.uv = v.uv;
            return o;
        }

        fixed4 frag (v2f i) : SV_Target
        {
            float2 texelSize = float2(1.0 / _ScreenParams.x, 1.0 / _ScreenParams.y);
            float2 uv = i.uv;

            fixed4 color = tex2D(_MainTex, uv) * 0.2270270270;
            color += tex2D(_MainTex, uv + float2(texelSize.x * 1.0, 0.0) * _BlurSize) * 0.1945945946;
            color += tex2D(_MainTex, uv - float2(texelSize.x * 1.0, 0.0) * _BlurSize) * 0.1945945946;
            color += tex2D(_MainTex, uv + float2(texelSize.x * 2.0, 0.0) * _BlurSize) * 0.1216216216;
            color += tex2D(_MainTex, uv - float2(texelSize.x * 2.0, 0.0) * _BlurSize) * 0.1216216216;
            color += tex2D(_MainTex, uv + float2(texelSize.x * 3.0, 0.0) * _BlurSize) * 0.0540540541;
            color += tex2D(_MainTex, uv - float2(texelSize.x * 3.0, 0.0) * _BlurSize) * 0.0540540541;

            return color;
        }
        ENDCG
    }

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag

        #include "UnityCG.cginc"

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

        struct v2f
        {
            float2 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
        };

        sampler2D _MainTex;
        float _BlurSize;

        v2f vert (appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            o.uv = v.uv;
            return o;
        }

        fixed4 frag (v2f i) : SV_Target
        {
            float2 texelSize = float2(1.0 / _ScreenParams.x, 1.0 / _ScreenParams.y);
            float2 uv =
推荐阅读:
  1. Unity shader实现高斯模糊效果
  2. Unity3D UGUI特效之Image高斯模糊效果

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

unity shader

上一篇:springmvc处理器映射器和适配器怎么配置

下一篇:Unity中如何优化字符串和文本

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》