您当前的位置: 首页 >  unity

Jave.Lin

暂无认证

  • 7浏览

    0关注

    704博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unity Shader GrabPass 使用注意的问题

Jave.Lin 发布时间:2020-03-04 17:14:17 ,浏览量:7

文章目录
  • 文档
  • GrabPass有两种写法
  • 区别
    • 使用GrabPass { } 的方式
      • 应用
      • Profiler > Frame Debugger
    • 使用GrabPass { "TheGrabTextureName" }方式
      • 两图对比一下
  • 不同Shader中使用了一样的GrabPass {"Name"}
  • 注意性能
    • CSharp
    • Shader

文档

关于Unity Shader中的GrabPass说明文档:

  • 官方的ShaderLab: GrabPass
  • CSDN其他博主翻译的ShaderLab: GrabPass
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)下载(我收藏到网盘了)

关注
打赏
1664331872
查看更多评论
0.1112s