Unity Shader 廣告牌閃光特效
阿新 • • 發佈:2019-02-07
原文連結:
這個可能是有點費,因為不是對一張圖片進行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,目的是為了讓掃光區域外的部分不接受掃光。
整體效果還不錯,效能消耗待檢驗。