本文參考自教程埋虹,并加上自己的一些心得體會浸锨。要想模擬現(xiàn)實中的波浪效果他膳,首先我們需要對頂點的y坐標進行偏移遗遵,并且希望y坐標能隨著時間變化而流暢變化屹耐,形成一種波的曲線厅须。那么,自然而然地直奋,我們想到了三角函數(shù)(sin能庆、cos)來實現(xiàn)效果:
v.vertex.y = sin(v.vertex.x + _Time.y);
我們將shader對應(yīng)的材質(zhì)設(shè)置到plane上,效果如下:
我們可以加上振幅脚线、周期等參數(shù)來進一步控制波浪的形狀搁胆,運動速度和運動軌跡:
float _Amplitude;
float _Wavelength;
float _Speed;
float k = 2 * UNITY_PI / _Wavelength;
v.vertex.y = _Amplitude * sin(k * (v.vertex.x + _Speed * _Time.y));
效果如下:
由于我們現(xiàn)在使用的mesh其實還是plane,所以法向量還是默認的(0,1,0)邮绿,我們需要根據(jù)波浪的運動去計算正確的法向量渠旁。由于現(xiàn)在波浪只在x方向上運動,所以只需要計算tangent即可船逮,binormal即為(0,0,1)顾腊。
有個tangent和binormal,我們就可以利用叉乘計算出法向量:
float k = 2 * UNITY_PI / _Wavelength;
float f = k * (v.vertex.x + _Speed * _Time.y);
v.vertex.y = _Amplitude * sin(f);
float3 tangent = float3(1, _Amplitude * k * cos(f), 0);
float3 binormal = float3(0, 0, 1);
float3 normal = cross(binormal, tangent);
有了正確的法向量挖胃,效果就好多了:
但是杂靶,只是普通的正弦波并不能完全反映出水面的波浪起伏,它沒有辦法描述水面隨著波浪前進后退的效果酱鸭。這里吗垮,我們借助大名鼎鼎的Gerstner wave來模擬這一效果。那么凹髓,我們也要在頂點的y改變時同時改變一下x:
float k = 2 * UNITY_PI / _Wavelength;
float f = k * (v.vertex.x + _Speed * _Time.y);
v.vertex.x += _Amplitude * cos(f);
v.vertex.y = _Amplitude * sin(f);
同樣地烁登,我們需要調(diào)整一下法向量的計算:
float3 tangent = float3(1 - _Amplitude * k * sin(f), _Amplitude * k * cos(f), 0);
float3 binormal = float3(0, 0, 1);
float3 normal = cross(binormal, tangent);
值得一提的是,我們需要注意調(diào)整振幅和波長的大小蔚舀,當振幅過大而波長過小時饵沧,容易出現(xiàn)波浪往上卷的現(xiàn)象(例如設(shè)置_Amplitude
為5锨络,_Wavelength
為10):
接下來,我們希望波浪不是僅僅沿著x方向運動狼牺,而是可以沿著設(shè)定的某一個方向向量運動羡儿。那么如法炮制:
float k = 2 * UNITY_PI / _Wavelength;
float2 d = normalize(_Direction);
float f = k * (dot(d, v.vertex.xz) + _Speed * _Time.y);
v.vertex.x += _Amplitude * d.x * cos(f);
v.vertex.y = _Amplitude * sin(f);
v.vertex.z += _Amplitude * d.y * cos(f);
當然,法向量也要隨之調(diào)整锁右,此時的binormal不再是(0,0,1):
float3 tangent = float3(1 - _Amplitude * k * d.x * d.x * sin(f), _Amplitude * k * d.x * cos(f), -_Amplitude * k * d.x * d.y * sin(f));
float3 binormal = float3(-_Amplitude * k * d.x * d.y * sin(f), _Amplitude * k * d.y * cos(f), 1 - _Amplitude * k * d.y * d.y * sin(f));
float3 normal = normalize(cross(binormal, tangent));
最后失受,我們希望能夠疊加多個Gerstner wave,讓波浪起伏的效果更加復(fù)雜化生動化咏瑟。我們可以先將一個wave用到的方向拂到,振幅,波長參數(shù)整合為一個4維向量码泞,然后抽出一個公共的函數(shù)來:
_WaveA ("Direction (2D), Amplitude, Wavelength", Vector) = (1,0,1,10)
float3 GerstnerWave (float4 wave, float3 p, inout float3 tangent, inout float3 binormal)
{
float2 direction = wave.xy;
float amplitude = wave.z;
float waveLength = wave.w;
float k = 2 * UNITY_PI / waveLength;
float2 d = normalize(direction);
float f = k * (dot(d, p.xz) + _Speed * _Time.y);
tangent += float3
(
-amplitude * k * d.x * d.x * sin(f),
amplitude * k * d.x * cos(f),
-amplitude * k * d.x * d.y * sin(f)
);
binormal += float3
(
-amplitude * k * d.x * d.y * sin(f),
amplitude * k * d.y * cos(f),
-amplitude * k * d.y * d.y * sin(f)
);
return float3
(
amplitude * d.x * cos(f),
amplitude * sin(f),
amplitude * d.y * cos(f)
);
}
float3 tangent = float3(1, 0, 0);
float3 binormal = float3(0, 0, 1);
float3 p = v.vertex.xyz;
v.vertex.xyz += GerstnerWave(_WaveA, p, tangent, binormal);
float3 normal = normalize(cross(binormal, tangent));
這樣兄旬,想疊加幾個波,就只需增加一下外部參數(shù)即可:
v.vertex.xyz += GerstnerWave(_WaveA, p, tangent, binormal);
v.vertex.xyz += GerstnerWave(_WaveB, p, tangent, binormal);
v.vertex.xyz += GerstnerWave(_WaveC, p, tangent, binormal);
如果你覺得我的文章有幫助余寥,歡迎關(guān)注我的微信公眾號(大齡社畜的游戲開發(fā)之路)-