打開網(wǎng)易新聞 查看精彩圖片

【USparkle專欄】如果你深懷絕技,愛“搞點(diǎn)研究”,樂于分享也博采眾長,我們期待你的加入,讓智慧的火花碰撞交織,讓知識的傳遞生生不息!

這是侑虎科技第1787篇文章,感謝作者楊超wantnon供稿。歡迎轉(zhuǎn)發(fā)分享,未經(jīng)作者授權(quán)請勿轉(zhuǎn)載。如果您有任何獨(dú)到的見解或者發(fā)現(xiàn)也歡迎聯(lián)系我們,一起探討。(QQ群:793972859)

作者主頁:

https://www.zhihu.com/people/wantnon

一、原理

參考這個論文:

《Real-time Simulation of Large Bodies of Water with Small Scale Details》

https://matthias-research.github.io/pages/publications/hfFluid.pdf

核心是這兩個公式:

打開網(wǎng)易新聞 查看精彩圖片

我在這篇《波動方程與淺水方程》中作了說明,轉(zhuǎn)貼如下:

淺水方程:

(1)動量方程

打開網(wǎng)易新聞 查看精彩圖片

(2) 質(zhì)量守恒

打開網(wǎng)易新聞 查看精彩圖片

其實(shí)淺水方程的動量方程,就是在NS方程的動量方程

打開網(wǎng)易新聞 查看精彩圖片

中令p=ρgη(η為海拔)得來,物理含義是表面隆起(或凹陷)產(chǎn)生壓強(qiáng)(或負(fù)壓強(qiáng))。

注意η和h的區(qū)別,h是水深,η是海拔,如果設(shè)河床高度為H,則有η=H+h。H是x,y的函數(shù),h是x,y,t的函數(shù)。

對于普通水可以忽略粘性,進(jìn)一步簡化為:

打開網(wǎng)易新聞 查看精彩圖片

論文中所用公式為:

打開網(wǎng)易新聞 查看精彩圖片

這其實(shí)就是淺水方程。說明如下:

D為物質(zhì)導(dǎo)數(shù),定義為

打開網(wǎng)易新聞 查看精彩圖片

將(2)式中物質(zhì)導(dǎo)數(shù)展開得

打開網(wǎng)易新聞 查看精彩圖片

可見就是淺水方程的動量方程忽略掉粘性項(xiàng)。再看(1)式,將其中物質(zhì)導(dǎo)數(shù)展開得

打開網(wǎng)易新聞 查看精彩圖片

又因?yàn)閔是標(biāo)量v是向量且均為空間的函數(shù),根據(jù)散度的運(yùn)算性質(zhì),有

打開網(wǎng)易新聞 查看精彩圖片

代入得

打開網(wǎng)易新聞 查看精彩圖片

可見就是淺水方程的質(zhì)量守恒方程。

注:

1. 淺水方程的動量方程(2)用的是海拔η ,質(zhì)量守恒方程(1)用的是水深h,這正是它可以適用于凹凸不平地形,模擬洪泛的原因。假如我們強(qiáng)行讓兩方程都用h,那就相當(dāng)于是假定海拔等于水深,即水底是平面,則不再具備模擬洪泛的能力,但仍可模擬水波。

質(zhì)量守恒方程:

打開網(wǎng)易新聞 查看精彩圖片

求解,對應(yīng)論文中:

打開網(wǎng)易新聞 查看精彩圖片

動量方程:

打開網(wǎng)易新聞 查看精彩圖片

求解,其中 求解對流項(xiàng):

打開網(wǎng)易新聞 查看精彩圖片

對應(yīng)論文中:

打開網(wǎng)易新聞 查看精彩圖片

由于沒給公式,我暫時(shí)忽略了這項(xiàng)。

求解壓力和外力項(xiàng):

打開網(wǎng)易新聞 查看精彩圖片

對應(yīng)論文中:

打開網(wǎng)易新聞 查看精彩圖片

二、MAC網(wǎng)格

論文中的離散化形式,含有:

打開網(wǎng)易新聞 查看精彩圖片

這種一半的項(xiàng),是因?yàn)橐肓朔Q作MAC網(wǎng)格的技巧,即將流入/流出速度看作是在cell的邊上,在處理散度相關(guān)問題時(shí),經(jīng)常用到。

下圖很直觀:

Eulerian Fluid Simulation Notes [Part 1]

https://quangduong.me/notes/eulerian_fluid_sim_p1/

Bridson's notes:nov17-cs533d-slides.ppt

https://www.cs.ubc.ca/~rbridson/courses/533d-fall-2005/nov17-cs533d-slides.pdf

打開網(wǎng)易新聞 查看精彩圖片

三、實(shí)現(xiàn)

最終是要用Shader實(shí)現(xiàn),但初期驗(yàn)證算法出于Debug方便考慮,還是先用Houdini實(shí)現(xiàn)。

當(dāng)然,我們可以真的在Houdini里建一個非?!熬呦蟮摹盡AC網(wǎng)格,就是每個格子表示一個cell,cell的邊界上可以附加速度向量。

但為了將來轉(zhuǎn)Shader更直接,我用的更接近二維數(shù)組的結(jié)構(gòu),我用一個二維點(diǎn)陣代表Grid,每個Point代表一個cell,Point有如下屬性:

f@h=0; f@u_r=0;//即u[i+1/2,j] f@w_d=0;//即w[i,j+1/2] f@h_r=0;//即h[i+1/2,j] f@h_d=0;//即h[i,j+1/2]

至于為啥沒有u_l(u[i-1/2,j]),w_u(w[i,j-1/2]),h_l(h[i-1/2,j]),h_u(h[i,j-1/2]),是因?yàn)楫?dāng)前Point的u_l其實(shí)就是左邊格子的u_r,即它已經(jīng)在左邊格子中存過的,就沒有必要在此格中再存一遍了。如果我們想獲得u_l,只需如下:

int ID=@ptnum;

int i=floor(ID/N);

int j=ID%N;

int ID_L=j*N+i-1;

float u_l=point(0,"u_r",ID_L)

w_u,h_l,h_u同理。

這也正是論文中這段:

打開網(wǎng)易新聞 查看精彩圖片

只給出

表達(dá)式,而沒有寫

表達(dá)式的原因。因?yàn)楫?dāng)前cell的

正是左邊cell和上邊cell(假設(shè)我的Grid是y軸向下)的

只要左邊cell和上邊cell已經(jīng)計(jì)算過,就可以直接訪問而無需在本cell中再重新計(jì)算一次。

同理,下面這段只給

也是同樣原因:

打開網(wǎng)易新聞 查看精彩圖片

然后,就只是抄公式了。

四、穩(wěn)定性

由于是離散模擬,而且用的是最簡單的顯式積分,所以會有數(shù)值穩(wěn)定性問題,論文中列了幾個措施可以提高穩(wěn)定性:

Overshooting Reduction:

在論文的2.2節(jié),提到有水與沒水交界處,h的振幅會因數(shù)值問題而被放大,導(dǎo)致邊緣出現(xiàn)尖刺甚至撕裂,用如下方法緩解:

打開網(wǎng)易新聞 查看精彩圖片

Stability Enhancements:

在論文的2.1.5節(jié),提到如下約束可提高穩(wěn)定性:

打開網(wǎng)易新聞 查看精彩圖片

五、參數(shù)對效果的影響

g,α,Δx,Δt對效果均有影響。

例如,不同α值對比:

α=0.5

 高度場流體模擬
打開網(wǎng)易新聞 查看更多視頻
高度場流體模擬

α=0.6

 高度場流體模擬
打開網(wǎng)易新聞 查看更多視頻
高度場流體模擬

可見,α =0.5和α=0.6相比,由于速度限制更狠,顯得更粘稠。

以上我們實(shí)現(xiàn)了凹凸不平地形上的淺水方程模擬,但忽略了對流項(xiàng)。

以下作了些改進(jìn),主要添加了對流項(xiàng)、渦度約束和邊界條件。

效果:

 高度場流體模擬
打開網(wǎng)易新聞 查看更多視頻
高度場流體模擬

六、添加對流項(xiàng)

對流項(xiàng):

打開網(wǎng)易新聞 查看精彩圖片

有兩種實(shí)現(xiàn)方式:一種是Gather方法,一種是直接離散化方法。

(一)Gather方法

實(shí)際上在Gather方法之前,還有一個Scatter方法,這兩種方法都是拋開對流的數(shù)學(xué)公式,而直接從公式背后的物理含義出發(fā)的模擬方法。Scatter方法就是把當(dāng)前cell的屬性傳輸出去,Gather方法就是把上游點(diǎn)的屬性傳輸給當(dāng)前cell。在《NS方程與2d流體模擬》中說過,Gather方法由于對GPU友好,更常用。

對流的Gather方法實(shí)現(xiàn),可以參考《游戲中的流體模擬(Fluid Simulation),技術(shù)美術(shù)教程 》。

由于我要在之前的基礎(chǔ)上加對流,而那個模擬過程中只使用到邊速度,但上面教程中的實(shí)現(xiàn)用的是cell速度,所以需要在邊速度和cell速度之間互轉(zhuǎn)。

過程如下:

Pass1:由邊速度計(jì)算cell速度。

Pass2:計(jì)算對流Advect。

1. 用9個格加權(quán)平均估算當(dāng)前cell平滑速度。

2. 將當(dāng)前cell平滑速度乘以dt再反向,以此作為偏移量去采樣上游目標(biāo)點(diǎn)的速度(用雙線性插值)。

3. 用采到的速度替換當(dāng)前cell的速度。

Pass3:由cell速度計(jì)算邊速度。

其中需要注意的點(diǎn)有:

1. 邊速度與cell速度之間的互轉(zhuǎn)。

我問的ChatGPT:

打開網(wǎng)易新聞 查看精彩圖片

由于兩個問題我是連續(xù)問的,所以它給出的公式也恰好是互逆的。我驗(yàn)證了一下,如果把P ass2屏蔽,只剩Pass1和Pass3,結(jié)果確實(shí)不受影響。

2. 無水處的速度

用9個cell的速度加權(quán)平均計(jì)算當(dāng)前cell平滑速度時(shí),不用管各cell是否有水,照加不誤。采樣上游點(diǎn)速度覆蓋當(dāng)前cell速度時(shí),也不用管上游點(diǎn)處是否有水,照覆蓋不誤。原因是,只要能保證無水處速度是0,上面的計(jì)算就都是合理的。至于如何保證無水處速度為0,見后面"邊界條件"一節(jié)。

3. 數(shù)值穩(wěn)定性及對流快慢和強(qiáng)度控制

以下兩項(xiàng)措施可以提高對流的數(shù)值穩(wěn)定性:

(1)縮短步長:將偏移-V*dt采樣改為偏移-V*dt*0.5采樣,這樣雖然會導(dǎo)致對流變慢(如果滴入墨水的話,體現(xiàn)為墨水?dāng)U散變慢),但有助于數(shù)值穩(wěn)定性。如果將步長減半的同時(shí)又不想對流變慢,可以在一幀內(nèi)將對流迭代兩次。

(2)減弱影響:將“用目標(biāo)點(diǎn)速度覆蓋當(dāng)前點(diǎn)速度”這一步,改為不完全覆蓋,而是按一定比例(如0.5)進(jìn)行混合。這樣雖然會使對流效果減弱,但也有助于數(shù)值穩(wěn)定性。

是否縮短步長和減弱影響,也未必總是出于數(shù)值穩(wěn)定性考慮,有時(shí)候?yàn)榱诵Ч?,也需要對對流的快速和?qiáng)度進(jìn)行控制。

4. 邊框處理

計(jì)算當(dāng)前cell平滑速度時(shí),9個cell中超出邊框者要去掉。采樣上游點(diǎn)時(shí),如果上游點(diǎn)超出邊框,則放棄當(dāng)前cell的對流計(jì)算。

(二)直接離散化方法

就是將

打開網(wǎng)易新聞 查看精彩圖片

展開為(設(shè)v=(u,w)):

打開網(wǎng)易新聞 查看精彩圖片

其中右邊各項(xiàng)離散化如下:

打開網(wǎng)易新聞 查看精彩圖片

這里用的是 迎風(fēng)格式,參考ChatGPT:

打開網(wǎng)易新聞 查看精彩圖片

同樣可以用縮短步長和減弱影響對對流快慢和強(qiáng)度進(jìn)行控制,以及提高數(shù)值穩(wěn)定性。

七、添加墨水

要想讓對流效果明顯地顯示出來,需要添加墨水。

方法如下:

1. 標(biāo)記一些cell為inkSource。

2. 每幀對標(biāo)為inkSource的cell追加ink值:ink+=inkAmount*dt

3. 在解算對流時(shí):

如果用的是Gather方法,則除了用上游點(diǎn)的速度覆蓋當(dāng)前點(diǎn)速度外,還要用上游點(diǎn)ink覆蓋當(dāng)前點(diǎn)ink。如果用的是直接離散化方法,則除了計(jì)算du、dw,(u,w)+=(du,dw),還要計(jì)算dink,ink+=dink。

4. 最后將ink可視化。

八、兩種對流方法效果對比

下面視頻中左邊為Gather,右邊為直接離散化:

 高度場流體模擬
打開網(wǎng)易新聞 查看更多視頻
高度場流體模擬

可見,大致效果接近,由于兩種方法很不同,所以基本可佐證實(shí)現(xiàn)是正確的。

九、添加渦度約束

方法在《NS方程與2d流體模擬》中已經(jīng)寫過。

需要注意的一點(diǎn)是,如果GetCurl函數(shù)中沒有除以Δx,則要在外面補(bǔ)上。另外為了讓效果與時(shí)間解耦,最終速度調(diào)整量還應(yīng)乘以Δt。

有無渦度約束對比:

打開網(wǎng)易新聞 查看精彩圖片

左: 無渦 度約束,右: 有渦度約束

可見,區(qū)別還是很明顯的。

十、添加邊界條件

1. 邊框處理

在之前的文章中,我沒有限制水不能流出邊框,所以水一直沿著河道流,永遠(yuǎn)不會漫上來。

這次,我加了水不能流出邊框的限制,只需將邊框視作障礙物,每幀末尾將邊框cell的邊速度和cell速度均標(biāo)為0即可。這在論文《hfFluid.pdf》中有寫:

打開網(wǎng)易新聞 查看精彩圖片

2. 使無水處速度為0

淺水方程本身是無法保證無水處速度為0的,因?yàn)閺?/p>

打開網(wǎng)易新聞 查看精彩圖片

來看,當(dāng)無水,即h=0時(shí),變?yōu)?/p>

打開網(wǎng)易新聞 查看精彩圖片

即仍會 由于地形本身有梯度而產(chǎn)生速度。 所以,要想讓無水處速度為0,只能通過人為添加約束實(shí)現(xiàn)。

其實(shí),上面Boundary Conditions這段已經(jīng)給出了方法,就是通過

打開網(wǎng)易新聞 查看精彩圖片

判斷右側(cè) 邊(i+1/2,j)是否為“岸”。 類似方法也可以判斷出左、上、下各邊是否為岸。

而且分析一下會發(fā)現(xiàn),這種判斷方法下,不僅岸與非岸的交界邊會被判為岸,岸上的邊也都會被判為岸,這正是我們想要的。于是對于判斷為岸的邊,我們在每幀末尾將其邊速度強(qiáng)制設(shè)為0,則可實(shí)現(xiàn)無水處速度為0的目標(biāo)。至于cell速度,由于它是由邊速度算出的,所以只要邊速度標(biāo)對了,cell速度自然也就對了。

另外,由于我們是在每幀末尾將無水處速度標(biāo)為0的,所以我將對流的計(jì)算放在最前面,以保證對流計(jì)算是在無水cell速度為0的情況下進(jìn)行的。

下圖是不加岸邊速度置0(左)與加岸邊速度置0(右),速度場及最終效果對比:

打開網(wǎng)易新聞 查看精彩圖片

左: 不 加岸邊速度置0,右: 加岸邊速度置0

看起來似乎差別不大,但有一點(diǎn),如果近看的話,會發(fā)現(xiàn)岸邊速度不置0的模擬結(jié)果,水會在岸邊隆起,不太合理,而加了岸邊速度置0的模擬結(jié)果,水與岸邊則是比較平滑的過度,如圖所示:

打開網(wǎng)易新聞 查看精彩圖片

左: 不加岸 邊速度置0,右: 加岸邊速度置0

參考文章:

《波動方程與淺水方程》

https://zhuanlan.zhihu.com/p/23947310903

《NS方程與2d流體模擬》

https://zhuanlan.zhihu.com/p/23421572373

《游戲中的流體模擬(Fluid Simulation),技術(shù)美術(shù)教程》

https://zhuanlan.zhihu.com/p/627468747

《hfFluid.pdf 》

https://matthias-research.github.io/pages/publications/hfFluid.pdf

文末,再次感謝 楊超wantnon 的分享, 作者主頁: https://www.zhihu.com/people/wantnon, 如果您有任何獨(dú)到的見解或者發(fā)現(xiàn)也歡迎聯(lián)系我們,一起探討。(QQ群: 793972859 )。

近期精彩回顧