溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Unity Shader后處理中如何實現高斯模糊

發布時間:2022-01-05 15:15:54 來源:億速云 閱讀:244 作者:小新 欄目:大數據

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 =
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女