先看效果:
飄動全是使用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
}
}
}
中間多次根據風力進行修正的地方,作者寫的蠻複雜,不寫那麼複雜,效果看起來也還行。