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