原文链接:
这个可能是有点费,因为不是对一张图片进行uv坐标的位移,然后两张图片合成的方法,而是在shader里面纯计算的方法实现的,可能有点费,性能暂未测试。
下面是shader代码:
Shader "MyShader/Flash" {
Properties {
_MainTex ("MainTexture", 2D) = "white" {}
_MaskTex ("MaskTexture", 2D) = "white" {}
_FlashColor ("FlashColor", Color) = (0.5,0.5,0.5,1)
_FlashAngle("FlashAngle",Range(0,180))=60
_xLength("xLength",float)=0.25
_Interval("Interval",float)=5
_BeginTime("BeginTime",float)=2
_offsetX("OffsetX",float)=0.15
_loopTime("loopTime",float)=0.7
}
SubShader {
Tags {
"RenderType"="Opaque"
}
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define UNITY_PASS_FORWARDBASE
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma multi_compile_fog
#pragma only_renderers d3d9 d3d11 glcore gles
#pragma target 3.0
uniform fixed4 _LightColor0;
uniform sampler2D _MainTex; uniform fixed4 _MainTex_ST;
uniform sampler2D _MaskTex; uniform fixed4 _MaskTex_ST;
uniform fixed4 _FlashColor;
fixed _FlashAngle;
fixed _xLength;
fixed _Interval;
fixed _BeginTime;
fixed _offsetX;
fixed _loopTime;
struct VertexInput {
fixed4 vertex : POSITION;
fixed3 normal : NORMAL;
fixed2 texcoord0 : TEXCOORD0;
};
struct VertexOutput {
fixed4 pos : SV_POSITION;
fixed2 uv0 : TEXCOORD0;
fixed4 posWorld : TEXCOORD1;
fixed3 normalDir : TEXCOORD2;
LIGHTING_COORDS(3,4)
UNITY_FOG_COORDS(5)
};
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.uv0 = v.texcoord0;
o.normalDir = UnityObjectToWorldNormal(v.normal);
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
fixed3 lightColor = _LightColor0.rgb;
o.pos = UnityObjectToClipPos( v.vertex );
UNITY_TRANSFER_FOG(o,o.pos);
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
}
//必须放在使用其的 frag函数之前,否则无法识别。
//核心:计算函数,角度,uv,光带的x长度,间隔,开始时间,偏移,单次循环时间
fixed inFlash(fixed angle,fixed2 uv,fixed xLength,int interval,int beginTime, fixed offX, fixed loopTime)
{
//亮度值
fixed brightness =0;
//倾斜角
fixed angleInRad = 0.0174444 * angle;
//当前时间
fixed currentTime = _Time.y;
//获取本次光照的起始时间
int currentTimeInt = _Time.y/interval;
currentTimeInt *=interval;
//获取本次光照的流逝时间 = 当前时间 - 起始时间
fixed currentTimePassed = currentTime -currentTimeInt;
if(currentTimePassed >beginTime)
{
//底部左边界和右边界
fixed xBottomLeftBound;
fixed xBottomRightBound;
//此点边界
fixed xPointLeftBound;
fixed xPointRightBound;
fixed x0 = currentTimePassed-beginTime;
x0 /= loopTime;
//设置右边界
xBottomRightBound = x0;
//设置左边界
xBottomLeftBound = x0 - xLength;
//投影至x的长度 = y/ tan(angle)
fixed xProjL;
xProjL= (uv.y)/tan(angleInRad);
//此点的左边界 = 底部左边界 - 投影至x的长度
xPointLeftBound = xBottomLeftBound - xProjL;
//此点的右边界 = 底部右边界 - 投影至x的长度
xPointRightBound = xBottomRightBound - xProjL;
//边界加上一个偏移
xPointLeftBound += offX;
xPointRightBound += offX;
//如果该点在区域内
if(uv.x > xPointLeftBound && uv.x < xPointRightBound)
{
//得到发光区域的中心点
fixed midness = (xPointLeftBound + xPointRightBound)/2;
//趋近中心点的程度,0表示位于边缘,1表示位于中心点
fixed rate= (xLength -2*abs(uv.x - midness))/ (xLength);
brightness = rate;
}
}
brightness= max(brightness,0);
//返回颜色 = 纯白色 * 亮度
fixed4 col = fixed4(1,1,1,1) *brightness;
return brightness;
}
fixed4 frag(VertexOutput i, fixed facing : VFACE) : COLOR {
fixed isFrontFace = ( facing >= 0 ? 1 : 0 );
fixed faceSign = ( facing >= 0 ? 1 : -1 );
i.normalDir = normalize(i.normalDir);
i.normalDir *= faceSign;
fixed3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
fixed3 normalDirection = i.normalDir;
fixed3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
fixed3 lightColor = _LightColor0.rgb;
// Lighting:
fixed attenuation = LIGHT_ATTENUATION(i);
fixed3 attenColor = attenuation * _LightColor0.xyz;
/// Diffuse:
fixed NdotL = max(0.0,dot( normalDirection, lightDirection ));
fixed3 directDiffuse = max( 0.0, NdotL) * attenColor;
fixed3 indirectDiffuse = fixed3(0,0,0);
indirectDiffuse += UNITY_LIGHTMODEL_AMBIENT.rgb; // Ambient Light
fixed4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
fixed3 diffuseColor = _MainTex_var.rgb;
fixed3 diffuse = (directDiffuse + indirectDiffuse) * diffuseColor;
// Emissive:
fixed4 _MaskTex_var = tex2D(_MaskTex,TRANSFORM_TEX(i.uv0, _MaskTex));
/// Final Color:
fixed3 finalColor = diffuse ;
fixed4 finalRGBA = fixed4(finalColor,1);
UNITY_APPLY_FOG(i.fogCoord, finalRGBA);
//传进i.uv等参数,得到亮度值
fixed tmpBrightness;
tmpBrightness =inFlash(_FlashAngle,i.uv0,_xLength,_Interval,_BeginTime,_offsetX,_loopTime);
//图像区域,判定设置为 颜色的A > 0.5,输出为材质颜色+光亮值
if(finalRGBA.w >0.5)
finalRGBA =finalRGBA+_FlashColor*tmpBrightness;
//空白区域,判定设置为 颜色的A <=0.5,输出空白
else
finalRGBA =fixed4(0,0,0,0);
return finalRGBA;
}
ENDCG
}
Pass {
Name "FORWARD_DELTA"
Tags {
"LightMode"="ForwardAdd"
}
Blend One One
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define UNITY_PASS_FORWARDADD
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#pragma multi_compile_fwdadd_fullshadows
#pragma multi_compile_fog
#pragma only_renderers d3d9 d3d11 glcore gles
#pragma target 3.0
uniform fixed4 _LightColor0;
uniform sampler2D _MainTex; uniform fixed4 _MainTex_ST;
uniform sampler2D _MaskTex; uniform fixed4 _MaskTex_ST;
struct VertexInput {
fixed4 vertex : POSITION;
fixed3 normal : NORMAL;
fixed2 texcoord0 : TEXCOORD0;
};
struct VertexOutput {
fixed4 pos : SV_POSITION;
fixed2 uv0 : TEXCOORD0;
fixed4 posWorld : TEXCOORD1;
fixed3 normalDir : TEXCOORD2;
LIGHTING_COORDS(3,4)
UNITY_FOG_COORDS(5)
};
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.uv0 = v.texcoord0;
o.normalDir = UnityObjectToWorldNormal(v.normal);
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
fixed3 lightColor = _LightColor0.rgb;
o.pos = UnityObjectToClipPos( v.vertex );
UNITY_TRANSFER_FOG(o,o.pos);
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
}
fixed4 frag(VertexOutput i, fixed facing : VFACE) : COLOR {
fixed isFrontFace = ( facing >= 0 ? 1 : 0 );
fixed faceSign = ( facing >= 0 ? 1 : -1 );
i.normalDir = normalize(i.normalDir);
i.normalDir *= faceSign;
fixed3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
fixed3 normalDirection = i.normalDir;
fixed3 lightDirection = normalize(lerp(_WorldSpaceLightPos0.xyz, _WorldSpaceLightPos0.xyz - i.posWorld.xyz,_WorldSpaceLightPos0.w));
fixed3 lightColor = _LightColor0.rgb;
// Lighting:
fixed attenuation = LIGHT_ATTENUATION(i);
fixed3 attenColor = attenuation * _LightColor0.xyz;
/// Diffuse:
fixed NdotL = max(0.0,dot( normalDirection, lightDirection ));
fixed3 directDiffuse = max( 0.0, NdotL) * attenColor;
fixed4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
fixed3 diffuseColor = _MainTex_var.rgb;
fixed3 diffuse = directDiffuse * diffuseColor;
/// Final Color:
fixed3 finalColor = diffuse;
fixed4 finalRGBA = fixed4(finalColor * 1,0);
UNITY_APPLY_FOG(i.fogCoord, finalRGBA);
return finalRGBA;
}
ENDCG
}
Pass {
Name "ShadowCaster"
Tags {
"LightMode"="ShadowCaster"
}
Offset 1, 1
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define UNITY_PASS_SHADOWCASTER
#include "UnityCG.cginc"
#include "Lighting.cginc"
#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile_shadowcaster
#pragma multi_compile_fog
#pragma only_renderers d3d9 d3d11 glcore gles
#pragma target 3.0
struct VertexInput {
fixed4 vertex : POSITION;
};
struct VertexOutput {
V2F_SHADOW_CASTER;
};
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.pos = UnityObjectToClipPos( v.vertex );
TRANSFER_SHADOW_CASTER(o)
return o;
}
fixed4 frag(VertexOutput i, fixed facing : VFACE) : COLOR {
fixed isFrontFace = ( facing >= 0 ? 1 : 0 );
fixed faceSign = ( facing >= 0 ? 1 : -1 );
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
FallBack "Diffuse"
}
这个是在mainTex基础上加了一个maskTex,目的是为了让扫光区域外的部分不接受扫光。
整体效果还不错,性能消耗待检验。