1. 程式人生 > >Unity Shader 廣告牌閃光特效

Unity Shader 廣告牌閃光特效

原文連結:

這個可能是有點費,因為不是對一張圖片進行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,目的是為了讓掃光區域外的部分不接受掃光。

整體效果還不錯,效能消耗待檢驗。