unity-frosted-glass-master毛玻璃效果

資源鏈接

資源鏈接:https://github.com/andydbc/unity-frosted-glass,注意:下載時,最好將防護軟件都關掉,不然有可能出現:壓縮包損壞無法解壓的問題
這是我下載再來的資源地址,大家可以用:https://download.csdn.net/download/f_957995490/12504874

參考

效果圖

效果圖

思路

  1. 利用 CommandBuffer 可以在攝像機渲染的幾個節點中插入,並執行一些操作。
    這裏的實現就是把 CommandBuffer 指定在渲染Transparent隊列前, 也就是此時已經渲染了天空盒,不透明物體 (opaque) 等渲染 *render queue* < Transparent (3000) 的物體,把此時攝像機的顏色緩衝區 複製到申請的一塊render texture中。
    然後把這個原始的rt的設置到shader全局紋理屬性中(CommandBuffer.SetGlobalTexture)。
  2. 把render texture用模糊的算法處理 , 比如:高斯模糊。此時這塊rt是全屏的模糊,但我們只需要局部區域要這個模糊效果。
    然後把這個模糊的rt的設置到shader全局紋理屬性中 (CommandBuffer.SetGlobalTexture)。
  3. 在想要模糊的地方丟一個box或平面模型,然後渲染時,指定渲染隊裏爲Transparent+(只要在 CommandBuffer之後就行)。 獲取模型頂點在屏幕空間的位置值 (也就是 [0, 1] 區間內),用這個值去採樣原始的rt和模糊後的rt,在用一個遮罩圖去插值指定哪些地方是需要鏤空的。

延伸:
除了CommandBuffer可以在指定的渲染節點內獲取攝像機的顏色緩衝區, 也可以用在渲染某個物體前用GrabPass的形式抓取攝像機當前的顏色緩衝區到一個rt上, 然後再用屏幕空間的位置去採樣這個rt。可以參考:Unity Shader-熱空氣扭曲效果
從顯存抓數據到內存都是比較耗性能的操作。

源碼分析

  • CommandBufferBlur.cs,這個腳本一定要掛在含有camera組件的go上,因爲要在攝像機渲染場景前回調 OnPreRender 函數。
using UnityEngine;
using UnityEngine.Rendering;

[ExecuteInEditMode]
[ImageEffectAllowedInSceneView]
[RequireComponent(typeof(Camera))]
public class CommandBufferBlur : MonoBehaviour
{
    Shader _Shader;

    Material _Material = null;

    Camera _Camera = null;
    CommandBuffer _CommandBuffer = null;

    Vector2 _ScreenResolution = Vector2.zero;
    RenderTextureFormat _TextureFormat = RenderTextureFormat.ARGB32;

    public void Cleanup()
    {
        if (!Initialized)
            return;

        _Camera.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, _CommandBuffer);
        _CommandBuffer = null;
        Object.DestroyImmediate(_Material);
    }

    public void OnEnable()
    {
        Cleanup();
        Initialize();
    }

    public void OnDisable()
    {
        Cleanup();
    }

    public bool Initialized
    {
        get { return _CommandBuffer != null; }
    }

    void Initialize()
    {
        if (Initialized)
            return;

        if (!_Shader)
        {
            _Shader = Shader.Find("Hidden/SeparableGlassBlur");//模糊的shader

            if (!_Shader)
                throw new MissingReferenceException("Unable to find required shader \"Hidden/SeparableGlassBlur\"");
        }

        if (!_Material)
        {
            _Material = new Material(_Shader);
            _Material.hideFlags = HideFlags.HideAndDontSave;
        }

        _Camera = GetComponent<Camera>();

        if (_Camera.allowHDR && SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.DefaultHDR))
            _TextureFormat = RenderTextureFormat.DefaultHDR;

        _CommandBuffer = new CommandBuffer();
        _CommandBuffer.name = "Blur screen";

        int numIterations = 4;

        Vector2[] sizes = {
            new Vector2(Screen.width, Screen.height),
            new Vector2(Screen.width / 2, Screen.height / 2),//降低分辨率,可以提高性能,和提高模糊效果,我的習慣是用>>1位移
            new Vector2(Screen.width / 4, Screen.height / 4),
            new Vector2(Screen.width / 8, Screen.height / 8),
        };

        for (int i = 0; i < numIterations; ++i)
        {
            int screenCopyID = Shader.PropertyToID("_ScreenCopyTexture");
            _CommandBuffer.GetTemporaryRT(screenCopyID, -1, -1, 0, FilterMode.Bilinear, _TextureFormat);//申請攝像機分辨率大小的rt
            _CommandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, screenCopyID);//將攝像機當前的rt複製給screenCopyID

            int blurredID = Shader.PropertyToID("_Grab" + i + "_Temp1");
            int blurredID2 = Shader.PropertyToID("_Grab" + i + "_Temp2");
            _CommandBuffer.GetTemporaryRT(blurredID, (int)sizes[i].x, (int)sizes[i].y, 0, FilterMode.Bilinear, _TextureFormat);//申請臨時的rt1 rt2,用來做模糊效果
            _CommandBuffer.GetTemporaryRT(blurredID2, (int)sizes[i].x, (int)sizes[i].y, 0, FilterMode.Bilinear, _TextureFormat);

            _CommandBuffer.Blit(screenCopyID, blurredID);
            _CommandBuffer.ReleaseTemporaryRT(screenCopyID);//釋放screenCopyID的rt

            _CommandBuffer.SetGlobalVector("offsets", new Vector4(2.0f / sizes[i].x, 0, 0, 0));//橫向模糊
            _CommandBuffer.Blit(blurredID, blurredID2, _Material);
            _CommandBuffer.SetGlobalVector("offsets", new Vector4(0, 2.0f / sizes[i].y, 0, 0));//縱向模糊
            _CommandBuffer.Blit(blurredID2, blurredID, _Material);

            _CommandBuffer.SetGlobalTexture("_GrabBlurTexture_" + i, blurredID);//模糊效果完成後,將其設置到全局紋理_GrabBlurTexture_1234,其他的FrostedGlass.shader中可以直接訪問
        }

        _Camera.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, _CommandBuffer);//在渲染Transparent隊列之前執行,確保渲染FrostedGlass(Transparent)的時候可以使用_GrabBlurTexture_1234

        _ScreenResolution = new Vector2(Screen.width, Screen.height);
    }

    void OnPreRender()
    {
        if (_ScreenResolution != new Vector2(Screen.width, Screen.height))
            Cleanup();

        Initialize();
    }
}
  • FrostedGlass.shader
Shader "Effects/FrostedGlass"
{
	Properties
	{
		_FrostTex ("Fross Texture", 2D) = "white" {}
		_FrostIntensity ("Frost Intensity", Range(0.0, 1.0)) = 0.5
	}
	SubShader
	{
		Tags { "RenderType"="Transparent" "Queue" = "Transparent" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

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

			struct v2f
			{
				float2 uvfrost : TEXCOORD0;
				float4 uvgrab : TEXCOORD1;  
				float4 vertex : SV_POSITION;
			};

			sampler2D _FrostTex;
			float4 _FrostTex_ST;

			float _FrostIntensity;

			sampler2D _GrabBlurTexture_0;
			sampler2D _GrabBlurTexture_1;
			sampler2D _GrabBlurTexture_2;
			sampler2D _GrabBlurTexture_3;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uvfrost = TRANSFORM_TEX(v.uv, _FrostTex);
				o.uvgrab = ComputeGrabScreenPos(o.vertex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				float surfSmooth = 1-tex2D(_FrostTex, i.uvfrost) * _FrostIntensity;
				
				surfSmooth = clamp(0, 1, surfSmooth);

				half4 refraction;

				half4 ref00 = tex2Dproj(_GrabBlurTexture_0, i.uvgrab);
				half4 ref01 = tex2Dproj(_GrabBlurTexture_1, i.uvgrab);
				half4 ref02 = tex2Dproj(_GrabBlurTexture_2, i.uvgrab);
				half4 ref03 = tex2Dproj(_GrabBlurTexture_3, i.uvgrab);

				float step00 = smoothstep(0.75, 1.00, surfSmooth);
				float step01 = smoothstep(0.5, 0.75, surfSmooth);
				float step02 = smoothstep(0.05, 0.5, surfSmooth);
				float step03 = smoothstep(0.00, 0.05, surfSmooth);

				refraction = lerp(ref03, lerp( lerp( lerp(ref03, ref02, step02), ref01, step01), ref00, step00), step03);
				
				return refraction;
			}
			ENDCG
		}
	}
}

參考鏈接

參考鏈接:https://blog.csdn.net/yangxuan0261/article/details/90348851

測試

條件

  1. 在場景攝像機上掛一個叫CommandBufferBlurComponent。如圖:
  2. 然後,創建一個Cube作爲測試,然後將shader:FrostedGlass的材質球賦到Cube上,即可。

效果

之後便可以看到響應的效果,如圖:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章