如何做一個水面波浪效果

本文參考自教程埋虹,并加上自己的一些心得體會浸锨。要想模擬現(xiàn)實中的波浪效果他膳,首先我們需要對頂點的y坐標進行偏移遗遵,并且希望y坐標能隨著時間變化而流暢變化屹耐,形成一種波的曲線厅须。那么,自然而然地直奋,我們想到了三角函數(shù)(sin能庆、cos)來實現(xiàn)效果:

                v.vertex.y = sin(v.vertex.x + _Time.y);

我們將shader對應(yīng)的材質(zhì)設(shè)置到plane上,效果如下:

如何做一個水面波浪效果1.gif

我們可以加上振幅脚线、周期等參數(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));

效果如下:

如何做一個水面波浪效果2.gif

由于我們現(xiàn)在使用的mesh其實還是plane,所以法向量還是默認的(0,1,0)邮绿,我們需要根據(jù)波浪的運動去計算正確的法向量渠旁。由于現(xiàn)在波浪只在x方向上運動,所以只需要計算tangent即可船逮,binormal即為(0,0,1)顾腊。
tangent=(dx, dy, 0) = (1, akcos(k(x + st)), 0)
有個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);

有了正確的法向量挖胃,效果就好多了:

如何做一個水面波浪效果3.gif

但是杂靶,只是普通的正弦波并不能完全反映出水面的波浪起伏,它沒有辦法描述水面隨著波浪前進后退的效果酱鸭。這里吗垮,我們借助大名鼎鼎的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);
如何做一個水面波浪效果4.gif

同樣地烁登,我們需要調(diào)整一下法向量的計算:
tangent=(dx, dy, 0) = (1 - aksin(k(s + st)), akcos(k(x + st)), 0)

float3 tangent = float3(1 - _Amplitude * k * sin(f), _Amplitude * k * cos(f), 0);
float3 binormal = float3(0, 0, 1);
float3 normal = cross(binormal, tangent);
如何做一個水面波浪效果5.gif

值得一提的是,我們需要注意調(diào)整振幅和波長的大小蔚舀,當振幅過大而波長過小時饵沧,容易出現(xiàn)波浪往上卷的現(xiàn)象(例如設(shè)置_Amplitude為5锨络,_Wavelength為10):

如何做一個水面波浪效果6.gif

接下來,我們希望波浪不是僅僅沿著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);
如何做一個水面波浪效果7.gif

當然,法向量也要隨之調(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));
如何做一個水面波浪效果8.gif

最后失受,我們希望能夠疊加多個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);
如何做一個水面波浪效果9.gif

如果你覺得我的文章有幫助余寥,歡迎關(guān)注我的微信公眾號(大齡社畜的游戲開發(fā)之路-

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末领铐,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宋舷,更是在濱河造成了極大的恐慌绪撵,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祝蝠,死亡現(xiàn)場離奇詭異音诈,居然都是意外死亡,警方通過查閱死者的電腦和手機绎狭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門细溅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人儡嘶,你說我怎么就攤上這事喇聊。” “怎么了蹦狂?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵誓篱,是天一觀的道長。 經(jīng)常有香客問我凯楔,道長窜骄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任啼辣,我火速辦了婚禮,結(jié)果婚禮上御滩,老公的妹妹穿的比我還像新娘鸥拧。我一直安慰自己党远,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布富弦。 她就那樣靜靜地躺著沟娱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪腕柜。 梳的紋絲不亂的頭發(fā)上济似,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音盏缤,去河邊找鬼砰蠢。 笑死,一個胖子當著我的面吹牛唉铜,可吹牛的內(nèi)容都是我干的台舱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼潭流,長吁一口氣:“原來是場噩夢啊……” “哼竞惋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起灰嫉,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤拆宛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后讼撒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浑厚,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年椿肩,在試婚紗的時候發(fā)現(xiàn)自己被綠了瞻颂。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡郑象,死狀恐怖贡这,靈堂內(nèi)的尸體忽然破棺而出厂榛,到底是詐尸還是另有隱情盖矫,我是刑警寧澤击奶,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布辈双,位于F島的核電站,受9級特大地震影響柜砾,放射性物質(zhì)發(fā)生泄漏湃望。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望证芭。 院中可真熱鬧瞳浦,春花似錦、人聲如沸废士。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽官硝。三九已至矗蕊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氢架,已是汗流浹背傻咖。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留达箍,地道東北人没龙。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像缎玫,于是被迫代替她去往敵國和親硬纤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354