通过 GrabPass 实现
Shader "Unlit/Glass"
{
Properties
{
_BumpAmt ("Distortion", Range (0,100)) = 10
_TintAmt ("Tint Amount", Range(0,1)) = 0.1
_BlurAmt ("Blur Amount", Range (0,1)) = 0.1
_MainTex ("Texture", 2D) = "white" {}
_BumpMap ("Normal Map", 2D) = "bump" {}
}
SubShader
{
Tags { "Queue" = "Transparent" } // 重要:使用透明队列保障其他物体已绘制在屏幕上
GrabPass { "_GrabBlurTexture" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 uv : TEXCOORD0;
float4 grabPos : TEXCOORD1;
float4 vertex : SV_POSITION;
};
float _BumpAmt;
float _TintAmt;
float _BlurAmt;
sampler2D _MainTex, _BumpMap;
float4 _MainTex_ST, _BumpMap_ST;
sampler2D _GrabBlurTexture;
float4 _GrabBlurTexture_TexelSize; // texture size, x:1.0/width y:1.0/height z:width w:height
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
o.uv.zw = TRANSFORM_TEX(v.uv, _BumpMap);
o.grabPos = ComputeGrabScreenPos(o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// 从 normalmap 中采样出凹凸值
float2 bump = UnpackNormal(tex2D(_BumpMap, i.uv.zw)).xy;
// 偏移量(*_TexelSize.xy 的意义是偏移值按抓取的纹理的单位像素进行缩放)
float2 offset = bump * _BumpAmt * _GrabBlurTexture_TexelSize.xy;
i.grabPos.xy = offset + i.grabPos.xy;
fixed4 col = tex2D(_GrabBlurTexture, i.grabPos.xy / i.grabPos.w); // 除以 w 后得到屏幕空间采样坐标
// blur (这是一个比较垃圾的模糊效果)
float blur = _BlurAmt / 100;
col += tex2D(_GrabBlurTexture, grabuv + float2(-blur, 0));
col += tex2D(_GrabBlurTexture, grabuv + float2(blur, 0));
col += tex2D(_GrabBlurTexture, grabuv + float2(0, blur));
col += tex2D(_GrabBlurTexture, grabuv + float2(0, -blur));
col = col / 5;
fixed4 tint = tex2D(_MainTex, i.uv.xy);
col = lerp (col, tint, _TintAmt);
return col;
}
ENDCG
}
}
}
通过 Command Buffers 实现
// 使用 command buffer 来生成 RT
public class ComdBuf : MonoBehaviour
{
// 在摄像机渲染之前执行
void OnWillRenderObject()
{
var cam = Camera.current;
CommandBuffer buff = new CommandBuffer();
// 申请 RT
int rtID = Shader.PropertyToID("_GrabBlurTexture");
buff.GetTemporaryRT(rtID, -1, -1, 0, FilterMode.Bilinear); // -1 for camera pixel width or height
// blit 方法接受 RT 的标识符 RenderTargetIdentifier (即 rtID)
buff.Blit(BuiltinRenderTextureType.CurrentActive, rtID); // 将当前渲染 RT 复制给 rtID
// 通过该命令使在 shader 中可通过 sampler2D _GrabBlurTexture 取得该 RT
buff.SetGlobalTexture(rtID, rtID); // 第一个参数是 shader 中的变量名,第二个是名称所标识的 RT
// 执行时机
cam.AddCommandBuffer(CameraEvent.AfterSkybox, buff);
}
}
接着可使用上面的 Shader 并去掉 GrabPass { “_GrabBlurTexture” } 即可达到一样的效果