热浪扭曲效果的实现,分两部分,一是抓图,二是扭曲扰动.其中难点在于抓图的处理,网上的解决方案有两种,在移动平台都有很多问题,只好自己实现了一种新的方案,效果还不错.
网上方案1. 用GrabPass抓图
GrabPass在有的手机上是不支持的...效率也是问题,所以...
代码可以看看:
Shader "Luoyinan/Distortion/HeatDistortion" { Properties { _NoiseTex ("Noise Texture (RG)", 2D) = "white" {} _MainTex ("Alpha (A)", 2D) = "white" {} _HeatTime ("Heat Time", range (0,1.5)) = 1 _HeatForce ("Heat Force", range (0,0.1)) = 0.1 } Category { Tags { "Queue"="Transparent+1" "RenderType"="Transparent" } Blend SrcAlpha OneMinusSrcAlpha AlphaTest Greater .01 Cull Off Lighting Off ZWrite Off SubShader { GrabPass { Name "BASE" Tags { "LightMode" = "Always" } } Pass { Name "BASE" Tags { "LightMode" = "Always" } CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest #include "UnityCG.cginc" struct appdata_t { float4 vertex : POSITION; fixed4 color : COLOR; float2 texcoord: TEXCOORD0; }; struct v2f { float4 vertex : POSITION; float4 uvgrab : TEXCOORD0; float2 uvmain : TEXCOORD1; }; float _HeatForce; float _HeatTime; float4 _MainTex_ST; float4 _NoiseTex_ST; sampler2D _NoiseTex; sampler2D _MainTex; v2f vert (appdata_t v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uvgrab = ComputeGrabScreenPos(o.vertex); o.uvmain = TRANSFORM_TEX( v.texcoord, _MainTex ); return o; } sampler2D _GrabTexture; half4 frag( v2f i ) : COLOR { // noise effect half4 offsetColor1 = tex2D(_NoiseTex, i.uvmain + _Time.xz*_HeatTime); half4 offsetColor2 = tex2D(_NoiseTex, i.uvmain - _Time.yx*_HeatTime); i.uvgrab.x += ((offsetColor1.r + offsetColor2.r) - 1) * _HeatForce; i.uvgrab.y += ((offsetColor1.g + offsetColor2.g) - 1) * _HeatForce; half4 col = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uvgrab)); // Skybox's alpha is zero, don't know why. col.a = 1.0f; half4 tint = tex2D( _MainTex, i.uvmain); return col*tint; } ENDCG } } // ------------------------------------------------------------------ // Fallback for older cards and Unity non-Pro SubShader { Blend DstColor Zero Pass { Name "BASE" SetTexture [_MainTex] { combine texture } } } } }
这种方法很坑爹,把场景再渲染一次?想想就很恐怖
我的方案: 后处理
换种思路,后处理其实就已经有了我们需要抓取的图,我们只需要渲染一个掩码图,就能实现局部的扭曲了,以前做次世代引擎的开发,很多特效都是后处理的实现的,比如人在水里面走水面泛起的涟漪,其实热浪扭曲也可以用类似的方法.
原理:
1.先用后处理实现全屏的扰动
2.用RenderTexture做实时的掩码图.
这样的话,效率开销只在两部分,一是后处理,二是把扭曲面片渲染到掩码图,
优化:
1.掩码图RenderTexture尽可能简单,关掉深度,抗锯齿等,用最简单的格式RenderTextureFormat.RGB565,黑白掩码图,不要alpha通道,掩码面片的shader可以用粒子的add shader
2.不需要扭曲的时候应该关闭掉扭曲用的后处理.不要一直开着.这个实现起来需要对掩码面片的存在有一个计数统计,才知道什么时候能关掉.
3.掩码图的比例一定要和屏幕保持一致,大小可设置为屏幕宽高的1/2或者1/4,
后处理的脚本:
后处理shader:
Shader "Luoyinan/ImageEffect/HeatDistortion" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _NoiseTex ("Noise Texture (RG)", 2D) = "white" {} _MaskTex ("Mask Texture", 2D) = "white" {} _HeatTime ("Heat Time", range (0,1.5)) = 1 _HeatForce ("Heat Force", range (0,0.1)) = 0.1 } SubShader { Pass { CGPROGRAM #pragma vertex vert_img #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest #include "UnityCG.cginc" float _HeatForce; float _HeatTime; uniform sampler2D _MainTex; uniform sampler2D _NoiseTex; uniform sampler2D _MaskTex; fixed4 frag(v2f_img i) : COLOR { // 为了效率,掩码图是黑白的,so... fixed mask = tex2D(_MaskTex, i.uv).r; // 扭曲效果 half4 offsetColor1 = tex2D(_NoiseTex, i.uv + _Time.xz*_HeatTime); half4 offsetColor2 = tex2D(_NoiseTex, i.uv - _Time.yx*_HeatTime); i.uv.x += ((offsetColor1.r + offsetColor2.r) - 1) * _HeatForce * mask; i.uv.y += ((offsetColor1.g + offsetColor2.g) - 1) * _HeatForce * mask; fixed4 renderTex = tex2D(_MainTex, i.uv); return renderTex; } ENDCG } } FallBack off }