距離之前的LBM方法已經過去了很長時間,后來在應用的時候發(fā)現我的方法有極大的錯誤。由于太想借鑒官方的模板,結果導致我沒有真正區(qū)分NS與LBM的不同。不過犯錯不要緊,根據實踐論,本來就是一個認識、實踐、再認識的循環(huán)過程?,F在這篇就是實踐再認識的總結階段了。我還是本著通俗的語言去講解,但這會有一個矛盾。數學中有句話說得好,“普適的代價是抽象”,那么通俗的講,必然有著片面性,以及本人能力有限,如果有錯誤或者過于片面的地方也歡迎大家補充和指正。廢話到此,直接開始吧。
(資料圖)
版本,官方對于流體和Niagara有著比較大的改動。(雖然都快出了?。┦紫?,就是HLSL有編譯報錯了,如果我沒記錯的話,你寫HLSL如果寫錯了字母和忘記了分號,那是沒有提醒的,只能極其折磨的一行一行的找,或者借助其他軟件幫忙。現在好多了,有提醒哪里錯了。再也沒有Debug半天發(fā)現字母寫錯了的那種欲哭無淚的感覺了。
其次就是流體官方進行了整理,簡潔了很多,沒有版本動不動上百的Emitter變量,雖然現在還是很多。然后各種功能也進一步整合到Module里了,煙霧的光照模塊刪除了(我目前只看了3D煙霧,其他的不太了解)。
這次我按照官方的模板,用LBM模擬速度場,該有的功能都有。在時間間隔為的情況下,不同的分辨率下兩者的在編輯器查看的耗時為(顯卡是6G 2060):
由此可見,LBM確實比官方的要更加的省,但好像又沒那么大的用,在我的預計中,最起碼不說優(yōu)化個十倍,七八倍總得有吧?,F實往往是殘酷的,不過也算是省了一些。當然,有可能是我代碼寫的不夠好,等下拿出來給大伙瞧瞧有沒有改進的地方。這也只是作為速度場的結果,本來我還想試試煙霧的渲染,看了下資料還涉及到LBM兩相流的問題,我實在暫時沒有太多的精力去深入了,這個先暫時放一下吧。速度場對于我接下來要做的事情,也夠用了。
LBM的基本原理之前文章提到過,我這里就不再贅述了。我們具體看是如何實現的吧。之前犯的錯誤我也會提及的。
Emitter Spawn
以LBM開頭的都是根據官方進行相關修改得到的,至于官方把之前雜七雜八的全部揉在一起,之前的文章也有所提及,這里就跳過不再贅述,也可以點進去看下,我只提及修改的部分,免得使文章過于冗雜。?
LBM Gas Initial Emitter?
從左側就可以看出我刪除了對于LBM不需要的Grid 3DCollection,由于LBM需要7個分布函數,分別對應粒子可以往七個方向跑。為了更直觀,就用UE的坐標系,X軸正向為右,Y軸正向為前,Z軸正向為上。那么七個方向分別為前后左右上下,再加上一個呆在原地的。那為啥不能斜著跑了,因為性能不夠,再加上斜著跑,估計開銷得更上一層樓,有人感興趣可以做下D3Q19或者D3Q27,也就是19個方向和27個方向。
注意別忘了把DistributionGrid的Num Attributes的數量設為7,不然你會得到一些奇奇怪怪的Bug。與其它通過英文單詞去訪問對應的Attributes不同,7個分布函數就用索引0、1、2、3、4、5、6來進行數據的讀取寫入。經過測試,如果你設置的Num Attributes為7,那么你一定要通過索引9(大于6)寫入數據,那么你寫的數據會被強制放在索引0中。
在ScalarGrid中我多加了個Force的屬性,用來表示外力,比如風力等等。
LBM Gas Debug Display
這個就是Debug用的嘛,把枚舉UI換成LBM的相關參數就可以了。
第一個就是我們Debug用的枚舉了,第二個是用于向Grid 3DCollection讀取寫入數據用到的,一共就改了這兩個枚舉UI,就一起拿出來了。
以前這玩意可以直接搜索到,但現在好像只能直接拖進Module里。
然后選擇紅線的選項才可以在變量中搜到我們自定義的枚舉。
Emitter Update
這部分沒什么改變,相關功能之前文章提到過,就不贅述了。
接下來我想先提提一些其他的東西,我剛剛接觸流體,看過很多大佬的文章,有些概念很難和實際(Niagara)聯系起來,好歹也是一個理科生,我想其他美術相關的同學可能和我有同樣的疑惑。如果看流體的相關文章,有一些相關的專業(yè)名詞,甚至再來點張量,實在有些勸退。流體的文章中,有拉格朗日視角,歐拉視角,甚至半拉格朗日視角,開始搞得我一頭霧水,其實就是描述流體運動的兩種不同視角。這在Niagara中的也有所體現。拉格朗日視角最好理解,也是最直觀的,就是把流體當作很多很多的粒子看待,這對平常我們做一些基礎特效最為熟悉不過的了。歐拉視角更像是一個萬能探測器,我只關心某一個空間位置,這個位置上流體的屬性如何變化,把這個萬能探測器放在某個點上,就可以得到這個點附近的流體屬性(溫度,密度,速度~~~)值。
在Niagara Simulation Stage中,對這兩中視角最好的體現就是Iteration Stage的兩種模式了,一種是Particle,相關計算是針對于每個粒子;一種就是Data Interface,而Data Interface我們經常用到的Grid 3D就是把空間分成一個一個小格子,計算是針對于每個小格子的。(版本還增加了一個Direct Set,這個暫時還沒研究)。
Init Scalar/Sim Grids
這個功能沒什么說的,就是初始化相關參數。
LBM SetFluidAttribute
這個模塊就是根據官方修改的,換成上面所提及過的枚舉變量就可以了。作用是向對應的Grid寫入相關屬性的數據,注意不要弄錯對應的Grid名字,以及分布函數的數據讀取寫入直接用索引編號就行了。
接下來就是與LBM相關的東西了,我先把公式放上來。這次加了一些東西。
演化方程:
平衡分布函數:
宏觀流體密度:
宏觀流體速度:
外力項:
相關參數對應著什么,之前文章提到過就不贅述了,這次與之前不同的地方是,我還加入了外力項。LBM外力項的加入也有好幾種方法,我用的是LBGK模型,還有其他例如He-Luo模型感興趣也可以嘗試一下,我只選擇其中一種。(其中)
Init Distribution/Raster Scalar/Raster Velocity Grid
在初始化流體時,我處理的方法是把初始流體密度設為(方便計算),將速度等于0代入到平衡分布函數作為初始的分布函數。權重系數我進行重新計算,作為D3Q7模型的權重系數與之前做的不一樣,我用的是1/4,1/8作為權重系數。
其它的初始值全部設為0就行了。
其實可以通過數值計算得到,如果沒有外力的情況下,這樣的初始值就是一個穩(wěn)定態(tài)。
Splat Particle Data Into Raster Grids
這個模塊就是接受另一個發(fā)射器傳過來的數據。
Pre Sim Velocity
這個模塊首先處理了邊界問題,主要有兩種邊界,一種是開放性邊界。一種是封閉邊界。開放性邊界我做了兩種方法的處理,一種是周期性邊界,從上面出去的流體會從下面出來;左邊流出的流體從右邊出來。還有一種到達邊界了,直接讓分布函數為0,視頻演示的就是直接為0的這種。封閉邊界很好理解,分布函數從哪里來回那里去,就是可以理解為反彈。這里也涉及交互的部分,就不展開了。
而后進行了一些可視化的處理,畢竟在3D空間去查看向量的值,確實需要一番功夫,官方已經幫我們做了。
再者就是數據的讀取與寫入了,還有各種外力。
LBM Get Fliud Attribute?
這個和之前寫入數據相對應嘛,有寫入數據就有讀取數據。也是根據官方改的,主要的核心我用圖片展示出來了,沒辦法展示全部,直接一張圖肯定密密麻麻看不清楚,如果分成小部分又要好多圖。做視頻太費時間了,圖文的信息密度大些,也花不了我多少時間。矛盾!所以我就展示核心部分了,其他的照著葫蘆畫瓢很快就能弄出來的。
LBM IntegrateForces
這一部分就是把之前的外力全部加在一起了,相對于官方的我刪除了速度,。然后寫入Force到Scalar Grid上。
Sourcing
這一模塊就是將另一個源發(fā)射器的數據,每幀寫入到Grid中。還有就是速度向量的可視化我放在這里了。
LBM Gas Get Particle Data from Raster Grid
這一部分官方的做法首先獲取速度,密度(溫度)的值,與另一個發(fā)射器傳過來的值進行處理(這種處理包括讓兩者Add或Max等)。這里我的處理我認為可能會有問題,這里大家自行判斷。我的處理就是將另一個源發(fā)射器傳遞的速度全部作為外力處理,一般我們對外力比如場力這樣處理很好理解,比如重力,電磁力,風力等等。但是對于另一個發(fā)射器傳過來的速度作為外力可能確實有些牽強,首先它并不是作用于全部流體,速度作為力這樣也比較不符合量綱。我只能強行給自己找個理由,傳過來的速度理解為在極短的時間內的速度變化值,就是力的體現。畢竟速度本身就不是一個瞬時值,一張行駛的汽車照片你是無法得出它的速度的。
總之,我就修改了速度,只獲取旁邊發(fā)射器的數據。其他的密度(溫度)沒有修改。這一塊是我最沒有底的部分,為什么要這么處理了,因為簡單啊。這一部分我再強調一邊,不具有太多參考性吧。
Core LBM
到LBM的核心部分了,首先獲取計算所需的外力Force,和初始宏觀速度。這里的初始(這個初始為了避免歧義是相對初始的意思,從經驗上看就是之前寫入Grid的Velocity數據,比如在第一幀計算時,獲取的是之前最開始速度初始值0;又或者是上一幀或者上一Simulation Stage的值,取決于實際情況,其實就盯著Grid里的數據如何變化就可以了。)代碼我已經寫好注釋了,就不多說了,如果大家覺得哪里還有優(yōu)化的地方可以提出來。說不定十倍性能優(yōu)化就達成了。
這里之前所犯的錯誤之一就是將NS的平流項與LBM的遷移項沒有理解清楚,無論是LBM的遷移還是NS的平流,可以說是對流體運動的闡釋。我之前的做法就是生搬硬套,兩個模塊都有,這一看就是錯誤的。當然還有其他許多問題,比如權重系數的的選取,格子聲速的選取等等。
這里還需要補充的地方是,對于開放邊界,我有兩個方法。目前是到達邊界直接為分布函數直接為0,被注釋掉的是周期性邊界條件,感興趣可以試試。
對于場景里與流體交互的東西,全部作為固體(或者說是封閉)邊界來看待,那么后面對交互有一些額外的處理。比如球(此處假設球作為交互物體)以一定速度向左運動,那么在這一幀里,就判斷有哪些格子的右側是球。那么該格子的速度的水平(左右方向上)分量是與球的速度一樣,注意是分量。比如某個格子經過計算得到的速度為(0,0,1),即此刻的速度是向上的,它的右邊是球,而此球以(-1,0,0)速度向左運動,那么格子最終速度是向左上方運動。差不多就是這個意思。?至于球內部,速度就直接是球的速度了。
還有一個棘手的問題,這個也折磨了我很長時間。就是LBM的速度不能太大,否則分分鐘就發(fā)散給你看。真是一點道理也不講。這個我看了下文章,有的就是加一個判斷,如果速度對于某一個值就按照速度的大小成比例減少。這我試了一下,有用,但還是不夠穩(wěn)定。最后我選擇在計算完平衡函數后,把平衡函數限制在(0,1)之間,就變得穩(wěn)定多了。其實這個也蠻好理解的,如果不考慮密度的變化(也就是流體不可壓縮的情況下),平衡分布函數是說明什么,在一個格子內有多少比例粒子往某個方向跑,那么無論格子速度是多離譜多大,平衡分布函數也是大于0的,只能無限接近0。那么反之也成立,也不可能超過1,超過粒子總數,也是只能無限接近1。
在處理這個問題也解答我另一個問題了,LBM是一種統(tǒng)計方法,對于流體,哪怕格子分的再?。ㄓ嬎銠C承受范圍內),實際在一個格子中的流體粒子也是極其多的。之前我在想為什么只能往隔壁格子跑了,假設其中一個粒子有著很大很大的向左運動速度,不能直接跨一個格子傳遞嘛。這個時候,我就忽略了統(tǒng)計的思想,哪怕真的某個粒子具有極大的向左速度,也會在運動過程中遭受其它粒子的阻礙,碰撞(或者稱之相互作用更加準確),那么它在單位時間跨一個甚至多個格子的概率是基本不可能發(fā)生的。像極了被生活磨平了棱角,但是這并不意味著毫無意義,此粒子向左的趨勢并沒有消失,而是在相互作用中,使得更多的粒子具有向左的趨勢。在平衡分布函數的表現上,即向左的平衡分布函數的值會增加。
這些也只是通過經典的牛頓視角去解釋LBM方法,只是我自己的理解?,希望大家辯證的看待(就是==如有錯誤,概不負責,只是作為一個參考,瘋狂疊甲)。??
后面就是寫入數據的過程,沒什么好說的。
LBM InnerRepel
這個模塊是為了美術效果后面加上去的。?具體的效果就是交互的物體內部,此效果只發(fā)生在物體內部?;诳臻g位置得得到一個向量,向量的方向是表現為遠離球心,大小就是距離球心越近,值就越大。就是將交互物體內部的東西排斥出去嘛,沒什么稀奇的。
RGBA這個是已經偏離了它命名的含義了,這個就是用作于向SimRT傳入數據的橋梁。
最后輸出的值為速度加上InnerRepelForce,然后再乘以一個系數,用來調節(jié)整體的大小。
Post Sim Scalars
這個模塊首先獲得上面提到過的RGBA值,傳遞給SimRT里面,然后還需要一張RT存儲存儲風場的一些信息,這個主要作用是用于坐標系的轉化。
這個詳細在下篇文章再講吧,涉及的東西有點多。其實很久之前就對Niagara的旋轉和一些變換想系統(tǒng)總結一下。之前看到四元數,旋轉向量,矩陣,歐拉角,旋轉角度以及各種坐標系變換就一頭霧水,似懂非懂。而且官方用的實例也蠻多的,這個我先放放,看實際用的多不,再考慮是否系統(tǒng)講講。
好了LBM就暫時告一段落了。
標簽: