Shader学习:气浪效果

效果如下:

实现思路:
这里首先使用GrabPass { “_ScreenTex” }来获取屏幕截图,截图会保存在_ScreenTex内。其次使用uv坐标到中心点的距离和圆的半径做比较,距离越接近半径的地方扭曲效果越强烈。最后扭曲效果的强弱就代表获取屏幕截图的纹素的坐标的偏移值。

步骤:
1.新建一个场景,然后通过菜单上的GameObject/3D Object/Quad来创建一个Quad,然后让摄像机看着这个Quad
2.新建一个材质球,并将它的shader设置为下面提供的shader
3.将材质球设为Quad所用的材质
4.通过材质球面板修改参数查看效果

Shader文件:

Shader "Custom/ShockWave" {
	Properties {
		_Radius ("Radius", Range(0, 0.45)) = 0.2
		_RingWidth ("Ring Width", Range(0, 0.1)) = 0.05
		_Fadeout("Fade Out", Range(0, 0.2)) = 0.05
	}
	SubShader {
		Tags { "Queue" = "Transparent+10" "IgnoreProjector" = "True" "RenderType"="Transparent" "ForceNoShadowCasting" = "True"}

		LOD 500

		GrabPass { "_ScreenTex" }

		Pass {
			ZWrite off
			Blend SrcAlpha OneMinusSrcAlpha

			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			fixed _Radius;
			fixed _RingWidth;
			fixed _Fadeout;
			sampler2D _ScreenTex;

			struct v2f {
				float4 pos : SV_POSITION;
				float4 srcPos : TEXCOORD0;
				half2 uv : TEXCOORD1;
			};

			v2f vert(appdata_img v) {
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.srcPos = ComputeGrabScreenPos(o.pos);
				o.uv = v.texcoord;
				return o;
			}

			fixed4 frag(v2f i) : SV_TARGET {
				// 计算到屏幕中的矢量
				half2 dir = i.uv - half2(0.5, 0.5);
				// 计算矢量的膜和圆半径的距离差值,这里这样写是为了避免开平方。因为是否使用开平方的结果在最终效果上肉眼几乎看不出区别。
				float smooth = abs(dot(dir, dir) - _Radius * _Radius);
				// 使用差值和圆环宽度进行比较。这里希望的效果是,差值越接近0,扭曲效果越大。
				smooth = 1 - smoothstep(0, _RingWidth, smooth);
				// 计算扭曲效果实际上获取了屏幕那个位置的纹素
				half2 offset = normalize(dir) * _RingWidth * smooth;
				fixed4 finalColor = tex2D(_ScreenTex, i.srcPos.xy / i.srcPos.w + offset);
				// 这里对透明度进行操作是为了圆环在远离中心点后逐步淡化的效果
				return fixed4(finalColor.rgb, smoothstep(0.05, 0.05 + _Fadeout, 0.5 - _Radius));
			}

			ENDCG
		}
	}
}