细草微风岸,危樯独夜舟 —— 唐 · 杜甫《旅夜书怀》
吟诗一首,再欣赏一下细草微风渲染效果。 没有录制一个完整循环,抖了一下,附送:Gif录制工具
王者荣耀整个地图植被只用了一张512px的Alpha贴图
一小块草mesh包含了uv和color,这里color是用来控制权重。
把color信息bebug渲染出来(开启下面shader注释color的二行), 可看出草的根部和顶部的摆动权重就是一个0到1的线性的变化,每根草的权重还有一定随机,仅仅用alpha通道来描述。如果做更复杂树的运动,可以R来主干运动,G树叶运动,B树枝运动。
草的沿着y轴生长,草的根部是y轴原点保持不动,y轴值越大,运动幅度越大(color.w),然后沿着x和z轴再做一个往复运动,这样就简单模拟出草的摇摆运动,说白了就是一个顶点动画。
往复运动,这里用一个正弦波实现。
正弦曲线公式可表示为y=Asin(ωx+φ)+k: A,振幅,最高和最低的距离,纵向拉伸压缩的倍数 ω,角速度,用于控制周期大小,单位x中的起伏个数 K,偏距,曲线整体上下偏移量 φ,初相,决定波形与X轴位置关系或横向移动距离(左加右减)
float tv = v.color.z * 3.14;
float offetX = _MiddleX + sin(_Time.y * _XSpeed + tv) * _XPower * v.color.w;
A = _XPower:控制波动效果对整体效果的影响大小。
A_Weight = v.color.w:通过color.w刷的y轴权重,y轴上每个点运动速率有变化,叠加_XPower影响
ωx = _Time.y * _XSpeed:用于控制周期大小,_Time表示时间周期 float4(t/20, t, t2, t3)
K = _MiddleX:曲线整体上下偏移量
φ = tv:通过color.z刷的,这样草运动有一定随机,而不是统一速度摇摆。
如下脑洞分析后人工重写的shader,可能与原始游戏效果有些差异。
Shader "S_Game_Scene/Grass_SWING_NoLightmap"
{
Properties
{
_MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
_Color ("Main Color", Vector) = (1,1,1,1)
_CutOff ("AlphaTest", Range(0, 1.01)) = 0.5
_MiddleX ("X中值", Float) = 0
_MiddleZ ("Z中值", Float) = 0
_XPower ("X方向摆动幅度", Float) = 1
_ZPower ("Z方向摆动幅度", Float) = 1
_XSpeed ("X方向摆动速度", Float) = 1
_ZSpeed ("Z方向摆动速度", Float) = 1
_YParam ("Y方向变化比例", Float) = 0.4
}
SubShader
{
Tags { "QUEUE" = "Transparent" "RenderType" = "Transparent" }
LOD 100
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 color : COLOR;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
//float4 color : COLOR;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed4 _Color;
float _Cutoff;
float _MiddleX;
float _MiddleZ;
float _XPower;
float _ZPower;
float _XSpeed;
float _ZSpeed;
float _YParam;
v2f vert (appdata v)
{
v2f o;
float4 modPos = float4(0, 0, 0, 0);
float tv = v.color.z * 3.14;
modPos.x = (v.vertex.x + ((_MiddleX + (sin(((_Time.y * _XSpeed) + tv)) * _XPower)) * v.color.w));
modPos.z = (v.vertex.z + ((_MiddleZ + (sin(((_Time.y * _ZSpeed) + tv)) * _ZPower)) * v.color.w));
modPos.y = (v.vertex.y - (sqrt((((modPos.x - v.vertex.x) * (modPos.x - v.vertex.x)) + ((modPos.z - v.vertex.z) * (modPos.z - v.vertex.z)))) * _YParam));
o.vertex = UnityObjectToClipPos(modPos);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
//o.color = v.color;
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv)*_Color;
clip(col.a - _Cutoff);
//col = i.color;
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}
属性上主要是x轴和z轴的运动幅度、速度控制
通过这个原理可以拓展出水面波纹、旗帜飘扬效果,以后再介绍吧~