资源链接:https://github.com/andydbc/unity-frosted-glass,注意:下载时,最好将防护软件都关掉,不然有可能出现:压缩包损坏无法解压的问题。
这是我下载再来的资源地址,大家可以用:https://download.csdn.net/download/f_957995490/12504874。
CommandBuffer
可以在摄像机渲染的几个节点中插入,并执行一些操作。CommandBuffer
指定在渲染Transparent队列前, 也就是此时已经渲染了天空盒,不透明物体 (opaque) 等渲染 *render queue* < Transparent (3000)
的物体,把此时摄像机的颜色缓冲区 复制到申请的一块render texture中。CommandBuffer.SetGlobalTexture
)。CommandBuffer.SetGlobalTexture
)。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();
}
}
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