第一种方式:
// 用于刀光的空气扭曲特效
Shader "Custom/SimpleHeatDistortion" {
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,1)) = 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 = UnityObjectToClipPos(v.vertex);
#if UNITY_UV_STARTS_AT_TOP
float scale = -1.0;
#else
float scale = 1.0;
#endif
o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
o.uvgrab.zw = o.vertex.zw;
o.uvmain = TRANSFORM_TEX( v.texcoord, _MainTex );
return o;
}
sampler2D _GrabTexture;
half4 frag( v2f i ) : COLOR
{
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));
col.a = 1.0f;
half4 tint = tex2D( _MainTex, i.uvmain);
return col*tint;
}
ENDCG
}// End Pass
}// End SubShader
// Fallback for older cards and Unity non-Pro
SubShader {
Blend DstColor Zero
Pass {
Name "BASE"
SetTexture [_MainTex] { combine texture }
}
}
}
}
第二种方式:
头文件
// 来自博客:http://console-dev.de/
#ifndef GRABPASSDISTORTION_GCINC
#define GRABPASSDISTORTION_GCINC
// _MainTex is the distortion texture and should use "Bypass sRGB Sampling" import setting.
sampler2D _MainTex;
// _MainTex tiling and offset properties.
float4 _MainTex_ST;
// _GrabTexture contains the contents of the screen where the object is about to be drawn.
sampler2D _GrabTexture;
// x=horizontal intensity, y=vertical intensity
// z=horizontal scrolling speed, w=vertical scrolling speed
float4 _IntensityAndScrolling;
// x=near distance at which distortions have full intensity
// y=far distance at which distortions have zero intensity
half2 _DistanceFade;
#if ENABLE_TINT
// Tinting the distorted area
half3 _Tint;
#endif
struct appdata_t
{
float4 vertex : POSITION;
half2 texcoord : TEXCOORD0;
fixed4 color : COLOR;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR; // a=distortion intensity multiplier
half4 texcoord : TEXCOORD0; // xy=distort uv, zw=mask uv
half4 screenuv : TEXCOORD1; // xy=screenuv, z=distance dependend intensity, w=depth
};
// ----------------------------------------------------------------------------
// Helper Functions
// ----------------------------------------------------------------------------
inline float2 Repeat(float2 t, float2 length)
{
return t - floor(t / length) * length;
}
inline float2 PingPong(float2 t, float2 length)
{
t = Repeat(t, length * 2);
return length - abs(t - length);
}
// ----------------------------------------------------------------------------
// Vertex Shader
// ----------------------------------------------------------------------------
v2f vert (appdata_t v)
{
v2f o = (v2f)0;
o.vertex = UnityObjectToClipPos(v.vertex);
o.color = v.color;
// texcoord.xy stores the distortion texture coordinates.
o.texcoord.xy = TRANSFORM_TEX(v.texcoord, _MainTex); // Apply texture tiling and offset.
o.texcoord.xy += _Time.gg * _IntensityAndScrolling.zw; // Apply texture scrolling.
// texcoord.zw stores the distortion mask texture coordinates.
// We don't want to scroll the mask, so we just use the original texture coords.
o.texcoord.zw = v.texcoord;
half4 screenpos = ComputeGrabScreenPos(o.vertex);
o.screenuv.xy = screenpos.xy / screenpos.w;
// Calculate distance dependend intensity.
// Blend intensity linearily between near to far params.
half depth = length(mul(UNITY_MATRIX_MV, v.vertex));
o.screenuv.z = saturate((_DistanceFade.y - depth) / (_DistanceFade.y - _DistanceFade.x));
o.screenuv.w = depth;
return o;
}
// ----------------------------------------------------------------------------
// Pixel Shader
// ----------------------------------------------------------------------------
fixed4 frag (v2f i) : COLOR
{
half2 distort = tex2D(_MainTex, i.texcoord.xy).xy;
// distort*2-1 transforms range from 0..1 to -1..1.
// negative values move to the left, positive to the right.
half2 offset = (distort.xy * 2 - 1) * _IntensityAndScrolling.xy * i.screenuv.z * i.color.a;
#if ENABLE_TINT
half3 tint = _Tint;
#endif
#if MASK
// _MainTex stores in the blue channel the mask.
// The mask intensity represents how strong the distortion should be for this pixel.
// black=no distortion, white=full distortion
half mask = tex2D(_MainTex, i.texcoord.zw).b;
offset *= mask;
#if ENABLE_TINT
// Push tint towards white where distortions are not applied.
// This makes the tint fade out using the mask.
tint = lerp(tint, half3(0.5,0.5,0.5), 1-mask);
#endif
#endif
#if ENABLE_CLIP
// Clip pixel if offset is really small. This makes masked particle
// distortions blend together slightly better.
clip(dot(offset,1) - 0.0001);
#endif
// get screen space position of current pixel
half2 uv = i.screenuv.xy + offset;
#if MIRROR_EDGE
// Mirror uv's when it goes out of the screen.
// This avoids streched seams at screen borders by introducing
// these kind of mirroring artifacts. It looks less disturbing than the border seams though.
uv = PingPong(uv, 1);
#endif
half4 color = tex2D(_GrabTexture, uv);
#if ENABLE_TINT
color.rgb *= tint * 2;
#endif
UNITY_OPAQUE_ALPHA(color.a);
#if DEBUGUV
color.rg = uv;
color.b = 0;
#endif
#if DEBUGDISTANCEFADE
color.rgb = lerp(half3(1,0,0), half3(0,1,0), i.screenuv.z);
#endif
//color.rgb = float3(fade,fade,fade)*15;
return color;
}
#endif // GRABPASSDISTORTION_GCINC
Shader 文件
// 热扭曲 —— GrabPass 实现方式
Shader "Custom/GrabPass Distortion (Layer)"
{
Properties
{
_MainTex ("Texture (R,G=X,Y Distortion; B=Mask; A=Unused)", 2D) = "white" {}
_Tint ("Tint (RGB)", Color) = (0.5,0.5,0.5,1)
_IntensityAndScrolling ("Intensity (XY); Scrolling (ZW)", Vector) = (0.1,0.1,1,1)
_DistanceFade ("Distance Fade (X=Near, Y=Far, ZW=Unused)", Float) = (20, 50, 0, 0)
[Toggle(MASK)] _MASK ("Texture Blue channel is Mask", Float) = 0
[Toggle(MIRROR_EDGE)] _MIRROR_EDGE ("Mirror screen borders", Float) = 0
[Enum(UnityEngine.Rendering.CullMode)] _CullMode ("Culling", Float) = 0
[Toggle(DEBUGUV)] _DEBUGUV ("Debug Texture Coordinates", Float) = 0
[Toggle(DEBUGDISTANCEFADE)] _DEBUGDISTANCEFADE ("Debug Distance Fade", Float) = 0
}
SubShader
{
Tags {"Queue" = "Transparent" "IgnoreProjector" = "True"}
Blend One Zero
Lighting Off
Fog { Mode Off }
ZWrite Off
LOD 200
Cull [_CullMode]
// 文档 http://docs.unity3d.com/Manual/SL-GrabPass.html
// Note: this form of grab pass (not specifying a texture name) will do the
// expensive screen grabbing operation for each object that uses it!
GrabPass{ }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma shader_feature MASK
#pragma shader_feature MIRROR_EDGE
#pragma shader_feature DEBUGUV
#pragma shader_feature DEBUGDISTANCEFADE
#define ENABLE_TINT 1
#include "UnityCG.cginc"
#include "GrabPassDistortion.cginc"
ENDCG
}
}
}