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上,即可。

效果

之后便可以看到响应的效果,如图:

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天富儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值