Shader GrabPass应用实例——实现扭曲效果

GrabPass简介

所谓GrabPass,可以在渲染所在对象之前,获取当前FrameBuffer中的图像,以供在后续Pass中进行处理,有这它就可以实现一些只能通过屏幕后处理进行操作,比如高斯Blur等。下面两篇文章写的不错。

https://docs.unity3d.com/Manual/SL-GrabPass.html

https://zhuanlan.zhihu.com/p/29378964(里面内容比较不错)

首先,先介绍在Shader Forge中如何进行使用,ShaderForge中是可以支持直接使用的,其中SceneColor就是对应的GrabTexture

以下对应ShaderForge生成的代码:

            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                o.pos = UnityObjectToClipPos( v.vertex );
                o.projPos = ComputeScreenPos (o.pos);
                COMPUTE_EYEDEPTH(o.projPos.z);
                return o;
            }
            float4 frag(VertexOutput i) : COLOR {
                float2 sceneUVs = (i.projPos.xy / i.projPos.w);
                float4 sceneColor = tex2D(_GrabTexture, sceneUVs);
////// Lighting:
////// Emissive:
                float3 emissive = tex2D( _GrabTexture, (sceneUVs * 2 - 1).rg).rgb;
                float3 finalColor = emissive;
                return fixed4(finalColor,1);
            }

其中可以看有两个Pass,其中一个是GrabPass,后面的代码可以通过_GrabTexture获取

GrabPass {}

另外,UnityAPI说明 中还可以使用以下的方式,但这种方式在Shader Forge中无法实现。

  • GrabPass { "TextureName" } grabs the current screen contents into a texture, but will only do that once per frame for the first object that uses the given texture name. The texture can be accessed in further passes by the given texture name. This is a more performant method when you have multiple objects using GrabPass in the scene.

其中我使用的Shader Forge1.38,如果使用默认的ScreenColor,计算出的屏幕UV是不对的

float3 emissive = tex2D( _GrabTexture, (sceneUVs * 2 - 1).rg).rgb;    //Shader Forge自动生成

half4 bgcolor = tex2Dproj(_GrabTexture, i.grabPos);     //使用官方做法

上行如果修改去掉*2-1操作就可以了

当然这里也可以通过,以下Scene UVs选项来解决这个问题,其值的范围是从0~1的



另外,Shader Forge中使用了Write Off也不是必要的


Tags { "Queue" = "Transparent" }

目前看有个限制,需要设置Quene为Transparent才能正常显示Grab到的内容。


相关特效实现参考以下

扭曲效果实现



需要注意的地方:

Normal Map选项一定选择,这样从法线空间获取颜色数值,这个选项与UnpackNormal是等价的

float3 _DistortMap_var = UnpackNormal(tex2D(_DistortMap,TRANSFORM_TEX(node_4942, _DistortMap)));

其核心是追加了一个扭曲的Offset


融合一些贴图之后,会更有科技感一些,主要是Texture使用Add的方式与之前的画面进行融合处理。


合屏幕深度

使用不同的扭曲权重

以下读取屏幕深度的方法

先在Vertex Shader中获取屏幕坐标

o.projPos = ComputeScreenPos (o.vertex);

COMPUTE_EYEDEPTH(o.projPos.z);

在片段Shader中获取当前片段坐标的屏幕深度

float sceneZ = LinearEyeDepth (UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos))));

但这种获取深度的做法就是当前面只能在最上层


一个综合的效果




猜你喜欢

转载自blog.csdn.net/FeiBin2013/article/details/80332341