畢業(yè)即失業(yè),想學(xué)習(xí)點(diǎn)知識(shí),看到了皮露露可不可的視頻和Unity | 流體模擬 - Navier Stokes - 為什么不開(kāi)大的文章 - 知乎
看到大佬們做的效果見(jiàn)獵心喜,故而開(kāi)始學(xué)習(xí),在此記錄一下權(quán)做學(xué)習(xí)筆記。
(資料圖)
由于流體模擬方程對(duì)我來(lái)說(shuō)研究之后除了增加了一點(diǎn)點(diǎn)數(shù)學(xué)常識(shí)并沒(méi)能對(duì)這個(gè)工程的理解有所幫助,所以這里大概是這怕文章中唯一一次提到這個(gè)公式了。
案例中流體的模擬是基于速度場(chǎng)的將整個(gè)圖片劃分網(wǎng)格通過(guò)速度場(chǎng)來(lái)對(duì)圖片的像素進(jìn)行采樣,在Unity中創(chuàng)建一張2D貼圖,每一個(gè)像素都是一個(gè)關(guān)于顏色的四維向量,我們采取顏色向量的前兩個(gè)值作為速度向量來(lái)對(duì)每個(gè)像素的速度進(jìn)行描述。這樣就可以通過(guò)片元著色器對(duì)速度場(chǎng)的變化進(jìn)行模擬了。
按照常規(guī)思維在模擬的時(shí)候應(yīng)該將當(dāng)前像素的速度和時(shí)間相乘計(jì)算新的坐標(biāo)并將當(dāng)前點(diǎn)的速度寫入新坐標(biāo)中,由于使用Unity的片元著色器對(duì)速度場(chǎng)進(jìn)行模擬,片元著色器只能寫入當(dāng)前像素的值,所以采用另一種方法同樣算出移動(dòng)距離后從反方向的地方獲取像素的速度并將其寫入當(dāng)前像素。
但是這樣做的話模擬精度似乎會(huì)有很嚴(yán)重的損失。在實(shí)驗(yàn)中若不對(duì)速度場(chǎng)進(jìn)行插值處理,速度場(chǎng)在邊界處似乎無(wú)法流動(dòng)。
在C#腳本中聲明了兩組RenderTexture,并在start中進(jìn)行初始化,貼圖vel用于儲(chǔ)存速度場(chǎng),col則是對(duì)圖像進(jìn)行流動(dòng)模擬所用。div則儲(chǔ)存散度場(chǎng)。
由于模擬是基于GPU的體現(xiàn)在Unity則是使用片元著色器(像素著色器)。所以需要通過(guò)shader進(jìn)行實(shí)現(xiàn)shader是在材質(zhì)上進(jìn)行工作所以需要為其創(chuàng)建“simMat”模擬材質(zhì)來(lái)進(jìn)行模擬。C#腳本若無(wú)特殊說(shuō)明將運(yùn)行在updata中,代碼將會(huì)每幀執(zhí)行一次。
由于在Unity的學(xué)習(xí)中通常使用UPR管線所以在學(xué)習(xí)時(shí)也嘗試在UPR的工程中進(jìn)行還原,個(gè)人代碼將會(huì)以注釋的形式進(jìn)行標(biāo)注
在C#腳本中將用于儲(chǔ)存速度場(chǎng)的貼圖vel0和平流速度系數(shù)傳入shader中進(jìn)行計(jì)算則會(huì)運(yùn)行shader中的相關(guān)pass并將運(yùn)算結(jié)果存如vel1中,在最后交換vel1和vel0這樣在下一幀時(shí)將基于上一幀的結(jié)果進(jìn)行運(yùn)算
在shader中頂點(diǎn)著色器將uv為當(dāng)前像素LRTB分別為上下左右相鄰的像素
dt是unity_的宏定義,tex2d()用于對(duì)貼圖進(jìn)行采樣,通過(guò)對(duì)當(dāng)前uv進(jìn)行采樣獲得速度并將其乘以時(shí)間獲得距離,再通過(guò)距離即可找到應(yīng)移動(dòng)到此點(diǎn)的速度值。將其寫入當(dāng)前像素
通過(guò)使用pass1進(jìn)行速度擴(kuò)散處理
此處為粘性擴(kuò)散,意為將速度擴(kuò)散至周圍的像素,因?yàn)榍拔奶岬降娜毕轃o(wú)此方法則速度場(chǎng)無(wú)法流動(dòng),此處采用了插值法對(duì)自己和周圍的像素采樣后取平均值,但是我未能理解為何為當(dāng)前像素賦予與幀時(shí)間相關(guān)的權(quán)重,以至于在處理中當(dāng)前像素將會(huì)是一個(gè)很小的權(quán)重(似乎與內(nèi)能損耗相關(guān)?)
完成這部分速度場(chǎng)就可以進(jìn)行流動(dòng),以下為我復(fù)刻的代碼。
標(biāo)簽: