3D优化之ShadowGun系列一:旗子飘扬效果实现方法及shader注解

先看效果:

飘动全是使用shader偏移顶点

的位置做的

几个点:

1、顶点数据的alpha值,标识了受风的权重。alpha越大,受风越厉害。

通过观察模型可以看出这点。而shader里这句也有说明。

以_Time作为参数,使用frac来取模,形成周期性的动画。

下面是注释后的shader

// - Unlit
// - Per-vertex (virtual) camera space specular light
// - SUPPORTS lightmap

Shader "MADFINGER/Environment/Lightmap + Wind" {
Properties {
    _MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
    _Wind("Wind params",Vector) = (1,1,1,1)
    _WindEdgeFlutter("Wind edge fultter factor", float) = 0.5
    _WindEdgeFlutterFreqScale("Wind edge fultter freq scale",float) = 0.5
}

SubShader {
    Tags {"Queue"="Transparent" "RenderType"="Transparent" "LightMode"="ForwardBase"}
    LOD 100
    
    Blend SrcAlpha OneMinusSrcAlpha
    Cull Off ZWrite Off
    
    
    CGINCLUDE
    #include "UnityCG.cginc"
    #include "TerrainEngine.cginc"
    sampler2D _MainTex;
    float4 _MainTex_ST;
    samplerCUBE _ReflTex;
    
    #ifndef LIGHTMAP_OFF        //lightmap是否开启。如果没有关闭lightmap。就给lightmap支持下。
    float4 unity_LightmapST;
    sampler2D unity_Lightmap;
    #endif
    
    float _WindEdgeFlutter;            //风导致旗帜震动的振幅
    float _WindEdgeFlutterFreqScale;  //风的时间流逝速度,影响频率,控制旗子反复摆动的周期

    struct v2f {
        float4 pos : SV_POSITION;
        float2 uv : TEXCOORD0;
        #ifndef LIGHTMAP_OFF        //开启lightmap的时候,要使用
        float2 lmap : TEXCOORD1;
        #endif
        fixed3 spec : TEXCOORD2;
    };

inline float4 AnimateVertex2(float4 pos, float3 normal, float4 animParams,float4 wind,float2 time)
{    
    // animParams stored in color
    // animParams.x = branch phase
    // animParams.y = edge flutter factor
    // animParams.z = primary factor
    // animParams.w = secondary factor

    float fDetailAmp = 0.1f;
    float fBranchAmp = 0.3f;
    
    // Phases (object, vertex, branch)
    float fObjPhase = dot(_Object2World[3].xyz, 1);  //这一行直接写1也行,_Object2World[3],一般情况下应该是0,0,0,1
    float fBranchPhase = fObjPhase + animParams.x;   //由于animParams.x是0,这个也是1
    
    float fVtxPhase = dot(pos.xyz, animParams.y + fBranchPhase);  //根据x,y,z,和振幅+1点乘。离远点越远,这个值越大。受振幅影响
    
    // x is used for edges; y is used for branches
    float2 vWavesIn = time  + float2(fVtxPhase, fBranchPhase );  //vWavesIn第一项是点的相位*时间流逝率,第二项就是时间+1.
    
    // 1.975, 0.793, 0.375, 0.193 are good frequencies
    float4 vWaves = (frac( vWavesIn.xxyy * float4(1.975, 0.793, 0.375, 0.193) ) * 2.0 - 1.0); // 将结果乘以频率,对一取模,然后乘以2,再减一
    
    vWaves = SmoothTriangleWave( vWaves );   //一个优化的正弦波计算。
    float2 vWavesSum = vWaves.xz + vWaves.yw; //振幅叠加,以免太正弦了。

    // Edge (xz) and branch bending (y)
    float3 bend = animParams.y * fDetailAmp * normal.xyz; //沿法线方向根据振幅和参数缩放一个值
    bend.y = animParams.w * fBranchAmp;                      //y根据受风能力,乘以一个参数
    pos.xyz += ((vWavesSum.xyx * bend) + (wind.xyz * vWavesSum.y * animParams.w)) * wind.w;  //再次根据受风能力进行影响。

    // Primary bending
    // Displace position
    pos.xyz += animParams.z * wind.xyz;  //根据受风能力,再次扩大。
    
    return pos;
}


    
    v2f vert (appdata_full v)
    {
        v2f o;
        
        float4    wind;
        
        float            bendingFact    = v.color.a;
        
        wind.xyz    = mul((float3x3)_World2Object,_Wind.xyz);      //风的方向转为物体坐标。wind参数的xyz表示风的世界坐标的方向。_Wind为风的个方向强度
        wind.w        = _Wind.w  * bendingFact;                        //每个顶点的颜色的alpha值表示此点受风变化的强度。旗子底部这个值较大。wind参数的w表示风力
        
        
        float4    windParams    = float4(0,_WindEdgeFlutter,bendingFact.xx);  //0,旗子振幅,每个顶点的受风强度值
        float         windTime         = _Time.y * float2(_WindEdgeFlutterFreqScale,1);  //风的时间流逝速度
        float4    mdlPos            = AnimateVertex2(v.vertex,v.normal,windParams,wind,windTime); //计算受风之后的位置
        
        o.pos = mul(UNITY_MATRIX_MVP,mdlPos);
        o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
        
        o.spec = v.color;
        
        #ifndef LIGHTMAP_OFF
        o.lmap = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
        #endif
        
        return o;
    }
    ENDCG


    Pass {
        CGPROGRAM
        #pragma debug
        #pragma vertex vert
        #pragma fragment frag
        #pragma fragmentoption ARB_precision_hint_fastest        //片元着色器选择低精度的计算方式。5.0以后抛弃掉 fragmentoption的声明。
        fixed4 frag (v2f i) : COLOR
        {
            fixed4 tex = tex2D (_MainTex, i.uv);
            
            fixed4 c;
            c.rgb = tex.rgb;
            c.a = tex.a;
            
            #ifndef LIGHTMAP_OFF
            fixed3 lm = DecodeLightmap (tex2D(unity_Lightmap, i.lmap));
            c.rgb *= lm;
            #endif
            
            return c;
        }
        ENDCG 
    }    
}
}


中间多次根据风力进行修正的地方,作者写的蛮复杂,不写那么复杂,效果看起来也还行。

猜你喜欢

转载自blog.csdn.net/zhjzhjxzhl/article/details/87566259