- 文档
- GrabPass有两种写法
- 区别
- 使用GrabPass { } 的方式
- 应用
- Profiler > Frame Debugger
- 使用GrabPass { "TheGrabTextureName" }方式
- 两图对比一下
- 不同Shader中使用了一样的GrabPass {"Name"}
- 注意性能
- CSharp
- Shader
关于Unity Shader中的GrabPass说明文档:
- 官方的ShaderLab: GrabPass
- CSDN其他博主翻译的ShaderLab: GrabPass
- GrapPass { }
- GrabPass { “TheGrabTextureName” }
两种写法的去写在哪呢。 文档中有说明,但是可能说的还是不够清楚。
我用自己总结的:
GrabPass { }
是每次Drawcall中的Shader的GrabPass使用时都会中屏幕内容抓取一次绘制的内容,并保存在默认的命为_GrabTexture的纹理中GrabPass { "TheGrabTextureName" }
是每一帧Drawcall中的Shader的GrabPass中,第一次调用该GrabPass抓取的内容,保存在TheGrabTextureName的纹理中,后面Drawcall或是pass调用的GrabPass { "TheGrabTextureName" }
只要TheGrabTextureName
纹理名字与之前的GrabPass { "TheGrabTextureName" }
中的TheGrabTextureName
相同,都不会再执行GrabPass的过程,而直接使用之前Grab好的纹理对象内容。
下面我在实际Unity测试项目中测试结果写下来。
区别我写了个测试用的,类似毛玻璃的模糊效果的Shader,如下:
使用GrabPass { } 的方式// jave.lin 2020.03.04
Shader "Custom/GrabTexBlur" {
Properties {
_Blur ("_Blur", Range(0, 1)) = 0
}
SubShader {
Tags { "Queue"="Transparent" "RenderType"="Transparent" }
GrabPass { }
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
float4 grabPos : TEXCOORD1;
float4 worldPos : TEXCOORD2;
};
sampler2D _GrabTexture;
float4 _GrabTexture_TexelSize;
fixed _Blur;
fixed3 blur(float2 uv) {
fixed3 sum = 0;
const int blurSize = 4;
const int initV = blurSize / 2;
const int maxV = initV + 1;
for (int i = -initV; i SubShader->pass中,之要是GrabPass的Pass,都会判断使用的格式,是否有名字,然后有名字的会将Grab出来的纹理放到一个hashTable中,类似的字典中[name] = grabTexture的方式存着,方便下次使用。
而RenderTexture就是我们说的RT,我们在Project视图下也可以手动创建RT。指定分辨率,滤波方式,是否记录深度,模板,像素格式,等属性。
那就是说,GrabPass其实类似下面的代码处理的过程
注意都是猜测,具体调用底层的渲染API这个需要使用一个分析工具才能确定
CSharp
RenderTexture grabRT = ...;
Camera c= ...;
c.targetTexture = grabRT;
c.Render();
// 单个材质shader的
Material mat = ...;
mat.SetTexture("_GrabTexture", grabRT");
// 所有shader的
Shader.SetGlobalTexture("_GrabTexture", grabRT);
Shader
sampler2D _GrabTexture;
而这个过程是很费(耗费性能)的
所以我们尽量能用GrabPass {“Name”} 就不用GrabPass{ }
刚开始我以为是RT的方式,后来发现一篇文章,虽然不是将GrabPass的,是将一般后效使用的MonoBehaviour类的回调OnRenderImage的方法下的Graphics.Blit,也是挺卡的,在一般的手机上。
这篇文章中有讲解:在使用Mali系列的Android手机。他用Mali Graphics Debugger看到底层渲染API的调用。 
图中可以看到Unity的Profiler中,有显示调用的是RenderTexture.GrabPixels
中MGD(Mali Graphics Debugger)中查看底层API
在glReadPixels的最后个参数不为空,则表示数据从显存传输到系统内存,从CPU到GPU的逆向传输,这是非常缓慢的过程,并且是阻塞模式。
2020.03.15 更新,在看到unity 的SIGGRAPH2011的某个文档有说明: GrabPass {“name”} • new in 3.4: only copies the color buffer once per frame (_Grab is shared)
所以确定,调用的就是glReadPixel
来读取ColorBuffer的像素的。 
在FORCE FIELD EFFECT那部分有说明,文档:SIGGRAPH2011 Special Effect with Depth.pdf 如果多年后,下载不了,链接无效了,可以点击这里(Passworld:cmte)下载(我收藏到网盘了)