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




