shader之——shadowGun代码分析

shadowGun是官方一个很早的demo,但是里面的东西真的是值得一学

  1.烟火,大多数人都是选择粒子来做这样的烟火,在shadeGun中只是用了一个片

搞定了如此真实的烟火,效率上面真的是比粒子好的不是一般的多。

 

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'


Shader "MADFINGER/Environment/Scroll 2 Layers Sine AlphaBlended" {
Properties {
    _MainTex ("Base layer (RGB)", 2D) = "white" {} //贴图1
    _DetailTex ("2nd layer (RGB)", 2D) = "white" {} //贴图2
    _ScrollX ("Base layer Scroll speed X", Float) = 1.0 //贴图1的x方向速度
    _ScrollY ("Base layer Scroll speed Y", Float) = 0.0 //贴图1的y方向速度
    _Scroll2X ("2nd layer Scroll speed X", Float) = 1.0 //贴图2的x方向速度
    _Scroll2Y ("2nd layer Scroll speed Y", Float) = 0.0 //贴图2的y方向速度
    _SineAmplX ("Base layer sine amplitude X",Float) = 0.5 //贴图1 x方向的扭动幅度
    _SineAmplY ("Base layer sine amplitude Y",Float) = 0.5 //贴图1 y方向的扭动幅度
    _SineFreqX ("Base layer sine freq X",Float) = 10 //贴图1 x方向的扭动速度
    _SineFreqY ("Base layer sine freq Y",Float) = 10 //贴图1 y方向的扭动速度
    _SineAmplX2 ("2nd layer sine amplitude X",Float) = 0.5 //贴图2 x方向的扭动幅度
    _SineAmplY2 ("2nd layer sine amplitude Y",Float) = 0.5 //贴图2 y方向的扭动幅度
    _SineFreqX2 ("2nd layer sine freq X",Float) = 10 //贴图2 x方向的扭动速度
    _SineFreqY2 ("2nd layer sine freq Y",Float) = 10 //贴图2 y方向的扭动速度
    _Color("Color", Color) = (1,1,1,1) //主颜色
    
    _MMultiplier ("Layer Multiplier", Float) = 2.0 //亮度
}

    
SubShader {
    Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
    
    Blend SrcAlpha OneMinusSrcAlpha
    Cull Off 
    ZWrite Off

    
    LOD 100
    
    CGINCLUDE
    #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
    #pragma exclude_renderers molehill    
    #include "UnityCG.cginc"


    sampler2D _MainTex;
    sampler2D _DetailTex;
    float4 _MainTex_ST;
    float4 _DetailTex_ST;

    float _ScrollX;
    float _ScrollY;
    float _Scroll2X;
    float _Scroll2Y;
    float _MMultiplier;
    
    float _SineAmplX;
    float _SineAmplY;
    float _SineFreqX;
    float _SineFreqY;

    float _SineAmplX2;
    float _SineAmplY2;
    float _SineFreqX2;
    float _SineFreqY2;
    float4 _Color;

    struct v2f {
        float4 pos : SV_POSITION;
        float4 uv : TEXCOORD0;
        fixed4 color : TEXCOORD1;
    };

    ///核心代码
    v2f vert (appdata_full v)
    {
        v2f o;
        o.pos = UnityObjectToClipPos(v.vertex);
        o.uv.xy = TRANSFORM_TEX(v.texcoord.xy,_MainTex) + frac(float2(_ScrollX, _ScrollY) * _Time);//贴图1的uv动画 frac(x) 返回标量或矢量的小数
        o.uv.zw = TRANSFORM_TEX(v.texcoord.xy,_DetailTex) + frac(float2(_Scroll2X, _Scroll2Y) * _Time);//贴图2的uv动画
        
        o.uv.x += sin(_Time * _SineFreqX) * _SineAmplX;//每个方向做曲线变化,sin里面的影响变化速度,x在外面的参数影响曲线范围
        o.uv.y += sin(_Time * _SineFreqY) * _SineAmplY;
        
        o.uv.z += sin(_Time * _SineFreqX2) * _SineAmplX2;
        o.uv.w += sin(_Time * _SineFreqY2) * _SineAmplY2;
        
        o.color = _MMultiplier * _Color * v.color; //亮度 * 颜色 * 顶点色
        return o;
    }
    ENDCG

    Pass {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag    
        fixed4 frag (v2f i) : COLOR
        {
            fixed4 o;
            fixed4 tex = tex2D (_MainTex, i.uv.xy);
            fixed4 tex2 = tex2D (_DetailTex, i.uv.zw);
            
            o = tex * tex2 * i.color;
                        
            return o;
        }
        ENDCG 
    }    
  }
}

 总结,frag函数里很简单,也是他的高效率的原因之一,shader优化的方向,把能在顶点计算的东西都在顶点里面去计算。

 

 

2.模拟雾效,淡进淡出效果

GodRays

这里的雾效不是指那种真的全局环境都受影响的大雾,而是一种现象:在视角逐渐接近它的时候,视野逐渐清晰。例如对于体积光,从远处看它可能会感觉很亮,但越接近亮度越小,越能看清后面的物体。这种效果可以很好地让玩家感觉到深度的变化。ShadowGun的解决方法是使用一个简单的网格(Fog planes)+透明纹理来模拟。一旦玩家靠近时,通过减淡颜色+使网格顶点移开(需要移开的原因是因为,即使是完全透明的alpha面也会消耗很多渲染时间,而这里的移开一般是把网格收缩变小,减少透明区域)的方法来模拟这个效果。

 

而如果要使用这个Shader,就需要在三维软件中处理那么Fog planes:

 

  • 顶点的透明度用于决定顶点是否可以移动(透明度为0表示不可移动,1为可移动)
  • 顶点法线决定移动的方向
  • 然后Shader通过计算与观察者的距离来控制雾面的淡入/淡出。

 

Shader "MADFINGER/Transparent/GodRays" {  
  
Properties {  
    _MainTex ("Base texture", 2D) = "white" {}  
    _FadeOutDistNear ("Near fadeout dist", float) = 10  //最近距离  
    _FadeOutDistFar ("Far fadeout dist", float) = 10000  //最远距离
    _Multiplier("Multiplier", float) = 1  //亮度
    _ContractionAmount("Near contraction amount", float) = 5  //顶点移动的速度
}  
  
      
SubShader {  
    Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }  
      
    Blend One One  
//  Blend One OneMinusSrcColor  
    Cull Off Lighting Off ZWrite Off Fog { Color (0,0,0,0) }  
      
    LOD 100  
      
    CGINCLUDE     
    #include "UnityCG.cginc"  
    sampler2D _MainTex;  
      
    float _FadeOutDistNear;  
    float _FadeOutDistFar;  
    float _Multiplier;  
    float _ContractionAmount;  
      
      
    struct v2f {  
        float4  pos : SV_POSITION;  
        float2  uv      : TEXCOORD0;  
        fixed4  color   : TEXCOORD1;  
    };  
      
    //核心代码
    v2f vert (appdata_full v)  
    {  
        v2f         o;  
        float3  viewPos = mul(UNITY_MATRIX_MV,v.vertex);  
        float       dist        = length(viewPos);  
        float       nfadeout    = saturate(dist / _FadeOutDistNear); //如果小于了最近距离,开始渐渐出现,如果大于最近距离,总返回为1
        float       ffadeout    = 1 - saturate(max(dist - _FadeOutDistFar,0) * 0.2);  //后面的值是 dist <=最远距离时 返回为0,大于后开始返回越接近1,所以用1-  
                                                  //结果就是 dist <=最远距离时  返回1,dist>最远距离时 渐渐为0  0.2是为0的速度
        //下面就是要把这两个数值结合成一个数值,直接将两个值相乘就可以
       //值A 值B   
         //1.当dist小于最小距离时候 它也必然小于最大距离 A返回的是0到1的数值 B返回的是1 所以相乘不影响结果
         //2.当dist大于最小距离 小于最大距离的时候       A 返回的是1       B返回的是1 所以相乘也不影响结果
         //3.当dist大于最大距离 它必然也大于最小距离     A 返回的是1       B返回的是1到0 所以相乘不影响结果

       ffadeout *= ffadeout; //乘以自身,影响曲线的变化速度
        nfadeout *= nfadeout; //乘以自身,影响曲线的变化速度
        nfadeout *= nfadeout; //乘以自身,影响曲线的变化速度
        nfadeout *= ffadeout; //实现了两个值的相乘,统一成一个数值,也是当作物体的透明度来使用 或者亮度来使用的一个0到1的值
        float4 vpos = v.vertex; //顶点
        vpos.xyz -= v.normal * saturate(1 - nfadeout) * v.color.a * _ContractionAmount; //沿顶点法线的反方向缩小模型,结合了顶点色的alpha值,需要动的顶点alpha为1,不需要动的顶点alpha为0 (一般起点不动,其他点向起点进行缩放)结合了强度;
                                                                                        //这里用1-nafadeout,因为当alpha值为1的时候,模型不需要缩放,而当alpha值表小的时候 开始缩放,当alpha值为0的时候 模型也缩放为0
        o.uv = v.texcoord.xy;
        o.pos = mul(UNITY_MATRIX_MVP, vpos);//顶点裁切(在缩放模型之后)
        o.color = nfadeout * v.color * _Multiplier; //颜色的亮度  用上面得出的亮度值 x 顶点色的颜色 x 强度
        return o;
      }
     ENDCG
 Pass 
{ 
   CGPROGRAM 

   #pragma vertex vert 
   #pragma fragment frag
   #pragma fragmentoption ARB_precision_hint_fastest  


   fixed4 frag (v2f i) : COLOR
   {
      return tex2D (_MainTex, i.uv.xy) * i.color;
    } 
    ENDCG 
   } 
 } 
}

 

  • 3.闪烁的灯光 这里涉及到比较喜欢的参数   灯光亮暗的时间长度控制

  • 跟上面想比 改了vert部分而已
  •  

    Blinking GodRays

  • Shader "MADFINGER/Transparent/Blinking GodRays" {
    
    Properties {
        _MainTex ("Base texture", 2D) = "white" {}
        _FadeOutDistNear ("Near fadeout dist", float) = 10 //最近距离
        _FadeOutDistFar ("Far fadeout dist", float) = 10000 //最远距离  
        _Multiplier("Color multiplier", float) = 1 //颜色亮度
        _Bias("Bias",float) = 0
        _TimeOnDuration("ON duration",float) = 0.5 //颜色为亮的时间
        _TimeOffDuration("OFF duration",float) = 0.5 //颜色为暗的时间
        _BlinkingTimeOffsScale("Blinking time offset scale (seconds)",float) = 5 //起始时间
        _SizeGrowStartDist("Size grow start dist",float) = 5 //
        _SizeGrowEndDist("Size grow end dist",float) = 50
        _MaxGrowSize("Max grow size",float) = 2.5
        _NoiseAmount("Noise amount (when zero, pulse wave is used)", Range(0,0.5)) = 0
        _Color("Color", Color) = (1,1,1,1)
    }
    
        
    SubShader {
        
        
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
        
        Blend One One
    //    Blend One OneMinusSrcColor
        Cull Off Lighting Off ZWrite Off Fog { Color (0,0,0,0) }
        
        LOD 100
        
        CGINCLUDE    
        #include "UnityCG.cginc"
        sampler2D _MainTex;
        
        float _FadeOutDistNear;
        float _FadeOutDistFar;
        float _Multiplier;
        float    _Bias;
        float _TimeOnDuration;
        float    _TimeOffDuration;
        float _BlinkingTimeOffsScale;
        float _SizeGrowStartDist;
        float _SizeGrowEndDist;
        float _MaxGrowSize;
        float _NoiseAmount;
        float4 _Color;
        
        
        struct v2f {
            float4    pos    : SV_POSITION;
            float2    uv        : TEXCOORD0;
            fixed4    color    : TEXCOORD1;
        };
    
        //核心代码
        v2f vert (appdata_full v)
        {
            v2f         o;
            
            float        time         = _Time.y + _BlinkingTimeOffsScale * v.color.b;        
            float3    viewPos        = mul(UNITY_MATRIX_MV,v.vertex);
            float        dist            = length(viewPos);
            float        nfadeout    = saturate(dist / _FadeOutDistNear);
            float        ffadeout    = 1 - saturate(max(dist - _FadeOutDistFar,0) * 0.2);
            float        fracTime    = fmod(time,_TimeOnDuration + _TimeOffDuration);//fmod(x,y):返回x/y的余数,如果y为0,结果不可预料
            float        wave            = smoothstep(0,_TimeOnDuration * 0.25,fracTime)  * (1 - smoothstep(_TimeOnDuration * 0.75,_TimeOnDuration,fracTime));//smoothstep(min,max,x):如果x=min,返回0;如果x=max,返回1;如果x在两者之间,返回0到1之间的数字
            float        noiseTime    = time *  (6.2831853f / _TimeOnDuration);
            float        noise            = sin(noiseTime) * (0.5f * cos(noiseTime * 0.6366f + 56.7272f) + 0.5f);//这个好懵逼 是不是复杂了点 只是改变一下曲线 也是拼 0—1 * ((0-0.5)+0.5) 结果是0到1 的参数
            float        noiseWave    = _NoiseAmount * noise + (1 - _NoiseAmount);//noise的程度
    
            float        distScale    = min(max(dist - _SizeGrowStartDist,0) / _SizeGrowEndDist,1); //放大模型的参数
            
                
            wave = _NoiseAmount < 0.01f ? wave : noiseWave;//当这个值小于0.01 就用wave,反之就用noiseWave
            
            distScale = distScale * distScale * _MaxGrowSize * v.color.a;//放大模型的参数
            
            wave += _Bias;//wave本为0到1的值,+上这个参数的时候 可以让灯闪的时候不至于全黑  把参数改变成_Bias 到 1+_Bias之间
            
            ffadeout *= ffadeout;
            
            nfadeout *= nfadeout;
            nfadeout *= nfadeout;
            
            nfadeout *= ffadeout;
            
            float4    mdlPos = v.vertex;
            
            mdlPos.xyz += distScale * v.normal;//正真的放大模型
                    
            o.uv        = v.texcoord.xy;
            o.pos    = mul(UNITY_MATRIX_MVP, mdlPos);
            o.color    = nfadeout * _Color * _Multiplier * wave;
                            
            return o;
        }
        ENDCG
    
    
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma fragmentoption ARB_precision_hint_fastest        
            fixed4 frag (v2f i) : COLOR
            {        
                return tex2D (_MainTex, i.uv.xy) * i.color;
            }
            ENDCG 
        }    
    }
    
    
    }

    亲,如果您觉得本文不错,愿意给我一些动力的话,请用手机扫描二维码即可向我打赏

                                             打赏

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值