Unity Shader 效果(1) :圖片流光效果

不少遊戲Logo中能夠看到這種流光效果,通常的實現方案就是對帶有光條的圖片uv根據時間進行移動,而後和原圖就行疊加實現,不過實現過程當中稍稍有點須要注意的地方。以前考慮過風宇衝的實現方式,可是考慮到shader中太多的計算,仍是放棄了。
markhtml

基礎版本

Shader "UICustom/ImageFlashEffect2"
{
    Properties
    {
        _MainTex ("Main Texture", 2D) = "white" {}

        _LightTex ("Light Texture", 2D) = "white" {}

        _LightColor("Light Color",Color) = (1,1,1,1)

        _LightPower("Light Power",Range(0,5)) = 1

        //每次持續時間,受Angle和Scale影響
        _LightDuration("Light Duration",Range(0,10)) = 1
        //時間間隔,受Angle和Scale影響
        _LightInterval("Light Interval",Range(0,20)) = 3
    }

    SubShader
    {
        Tags 
        {
            "Queue"="Transparent" 
            "IgnoreProjector"="True" 
            "RenderType"="Transparent"
        }

        Cull Off
        Lighting Off
        ZWrite Off
        Fog { Mode Off }
        Offset -1, -1
        Blend SrcAlpha OneMinusSrcAlpha 
        AlphaTest Greater 0.1

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

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float2 lightuv : TEXCOORD1;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            sampler2D _LightTex ;
            float4  _LightTex_ST;

            half _LightInterval ;
            half _LightDuration ;

            half4 _LightColor ;
            half _LightPower ;

            half _LightOffSetX ;
            half _LightOffSetY ;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                fixed currentTimePassed = fmod(_Time.y,_LightInterval);
                //uv offset, Sprite wrap mode need "Clamp"
                fixed offsetX = currentTimePassed / _LightDuration;
                fixed offsetY = currentTimePassed / _LightDuration;
                fixed2 offset ;
                offset.x = offsetX - 0.5f;
                offset.y = offsetY - 0.5f;

                o.lightuv = v.uv  + offset ;

                o.uv         = TRANSFORM_TEX(v.uv, _MainTex);
                o.lightuv    = TRANSFORM_TEX(o.lightuv, _LightTex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 mainCol   = tex2D(_MainTex, i.uv);
                fixed4 lightCol  = tex2D(_LightTex, i.lightuv);
                lightCol *= _LightColor ;

                //need blend
                //lightCol.rgb *= mainCol.rgb ;
                fixed4 fininalCol ;
                fininalCol.rgb   = mainCol.rgb +  lightCol.rgb * _LightPower;
                fininalCol.a =  mainCol.a * lightCol.a ;
                return fininalCol ;
            }
            ENDCG
        }
    }
}

須要注意的點:git

  1. 時間間隔問題
fixed currentTimePassed = fmod(_Time.y,_LightInterval);
//uv offset, Sprite wrap mode need "Clamp"
fixed offsetX = currentTimePassed / _LightDuration;
fixed offsetY = currentTimePassed / _LightDuration;

offsetX 、offsetY實際上是0~_LightInterval的數值,須要設置圖片爲光線圖片的Wrap模式爲Clamp,才能實現時間間隔控制github

  1. 色彩融合
    Pixel着色器中frag()函數是經過原始顏色和光線顏色疊加的方式實現的,也有將光線顏色和原圖混合後再疊加的作法,這個我以爲看實際應用。注意alpha的控制

優化

1. 增長角度和大小控制

基本版本的實現中光線只能根據流光圖片中亮線的寬度和方向決定實際的滾動方向和大小。有時候若是須要常常調節方向和大小,能夠考慮加入相關因素。流光的Uv是經過原圖當前Uv加上時間軸參數得到,能夠考慮經過修改流光uv的計算方式來實現。以下面代碼。不過這種方式增長了必定計算量,不須要的話則直接跳過。還有一點就是流光貼圖必須是垂直或者水平。app

float2 base = v.uv ;
base.x -= _LightOffSetX ;
base.y -= _LightOffSetX ;
base = base / _LightScale ;

float2 base2 = v.uv;
base2.x  = base.x * cosInRad - base.y * sinInRad ;
base2.y  = base.y * cosInRad + base.x * sinInRad ;

o.lightuv = base2 + offset ;
材質複用

只是想不一樣的圖片都是使用相同的材質,應該保證每一個圖片的效果均可以獨立進行修改保存,能夠考慮每張圖片都建立一份材質,而後修改其參數。less

void UpdateParam()
   {
       if (Material == null)
       {
           Debug.LogWarning("Metarial is miss");
           return;
       }

       if (mGraphic == null)
       {
           mGraphic = GetComponent<MaskableGraphic>();
       }

       if (mGraphic is Text)
       {
           Debug.LogError("FlashEffec need component type of Image、RawImage");
           return;
       }

       if (mDynaMaterial == null)
       {
           mDynaMaterial = new Material(Material);
           mDynaMaterial.name = mDynaMaterial.name + "(Copy)";
           mDynaMaterial.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
       }

       if (mDynaMaterial == null)
       {
           return;
       }

       mDynaMaterial.mainTexture = null;
       if (OverrideTexture != null)
       {
           mDynaMaterial.mainTexture = OverrideTexture;

           if (mGraphic is RawImage)
           {
               RawImage img = mGraphic as RawImage;
               img.texture = null;
           }
           else if (mGraphic is Image)
           {
               Image img = mGraphic as Image;
               img.sprite = null;
           }
       }
       else
       {
           mDynaMaterial.mainTexture = mGraphic.mainTexture;
       }

       if (Duration > Interval)
       {
           Debug.LogWarning("ImageFlashEffect.UpdateParam:Duration need less Interval");
           Interval = Duration + 0.5f;
       }

       mDynaMaterial.SetColor("_LightColor", Color);
       mDynaMaterial.SetFloat("_LightPower", Power);
       mDynaMaterial.SetFloat("_LightScale", Scale);
       mDynaMaterial.SetFloat("_LightAngle", Angle);
       mDynaMaterial.SetFloat("_LightDuration", Duration);
       mDynaMaterial.SetFloat("_LightInterval", Interval);
       mDynaMaterial.SetFloat("_LightOffSetX", OffSet);
       mGraphic.material = mDynaMaterial;
       mGraphic.SetMaterialDirty();
   }

下載:https://github.com/carlosCn/Unity_Image_Flash_Effectide

參考

http://blog.csdn.net/qq992817263/article/details/51200424
http://qkxue.net/info/169189/Unity-Simple-Shaderlab-uGui-shader-1函數

相關文章
相關標籤/搜索