這兩天挪威大神不在,感覺有點寂寞。剛剛學習完他的一個牛逼工具Volume Lattice。鑒於他直接把這個工具已經拿到Orbolt里面賣錢了,我在這就只講講自己的學習理解,代碼什么的就不在這上了,何況要是理解了方法其實零代碼也能夠自己實現出來。這里是他的工具連接,給這位牛逼的外國師傅做做廣告:Volume Lattice
效果圖:
這個工具的思路主要是使用點雲來代替voxel,通過拉伸點雲之后,求出每個點的位移向量,再把這個向量值轉變為體積,最后使用這些向量來計算density新的位置。
制作步驟這樣的:
1:在需要拉伸的volume里面均勻隨機的撒上點,這里可以使用PointFromVolume和PointJitter來完成,密度可以是和需要變形的volume分辨率相關,當然還有很多別的方法,自己玩吧。這樣算是完成了將volume暫時轉化為點雲的過程,其中點雲的密度與之后拉伸的精確程度相關性不是特別大,因為晶格變形的時候我們的晶格控制點也不會太多,但是點雲數量也不能過於稀疏。另外如果需要做變形動畫的話,建議還是把點雲數量開高一點,要不然動畫的時候會有抖動。
2:通過自帶的lattice來拉伸點雲。這里挪威大神自己做了一個節點來完成這一步,仔細分析完之后其實就是lattice里面的Liner Interplolation,雖然個人覺得自己再寫一個確實有點多次一舉,但是學習的樂趣就在於總能發現一些以前從來沒接觸和了解的東西。為了了解他的方法,我找到了wiki里面對於雙線性插值的方法(bilinear interpolation),了解到只要我們使用的是通過盒子來做Lattice的方法其實就是傳統圖像學里面插值方法的一種,最常見效率和效果平衡最好的是三線性(因為我們有三個維度)插值方法,另外還有spline插值方法,Houdini的lattice里面對於比較柔和的插值方法使用的是Bezier插值方法。
下面的圖解釋了雙線性插值在平面維度的原理,圖有點簡單純靠悟性了,如果不懂這里是wiki鏈接:Bilinear Interpolation
3:言歸正傳,做好點雲的lattice之后,用wrangle也好還是vop也好,把每個點對應的位移displace計算出來並寫到被變形后的點雲里面。用變形后點雲的Bounding Box來生成類似步驟1的點雲,把拉伸后點雲的displace傳遞給新點雲,這樣displace就以點雲的形式充滿的新的box,再用VolumeFromAttrib把displace變為volume值。值得一提的是因為不論怎樣點也是不會完全填充在體積里面的,所以當直接把Attrib轉換給Volume后,其實Volume里面該值是很不均勻的,在同一個切面下有些地方有,有些地方完全沒有。這種情況下就需要使用Volume Blur來把數值做個均勻,測試的結果是使用兩層blur效果比較好,第一次將沒有數值的地方使用Minimum來填充上,第二次是用Average的方法讓數值變化更加柔和。其實blur的效果好不好直接決定了之后Volume變形的效果好不好,因為這個步驟才真正意義上把變形的數據填充到了整個volume里面:
4:新的box大小就是變形后volume的大小。依照這個大小新建一個空的volume,在vop或者warngle里面用Pos先讀取displace的volume值得到一個向量v,所以我們知道當前Pos的density值的位置是在原來Pos - displace的地方。就着算出來的這個向量值在原來沒有變形的volume里面取出density值賦予到這個新box在pos的位置上。這樣就完成變形了。
總結一下:
關於volume里面的值是和sop里面幾何體下面的值是有很大區別的,voxel和點的區別在於,當volume的盒子和division確定后每一個voxel就是固定的死的,這個有點像我們顯示器上的像素點,數據(顏色值之於像素點)變與不變與voxel無關,它只負責表現出來。而點的所有數值是跟着點走的,而點的位置也是通過P的變量寫在自己身上的,所以針對與某一位置的數據如果是在點上,不論位置怎樣變換,我們只要找到那個點就能拿到所有的數據,這樣通過點為媒介我們可以說某一個值變換了位置。而在voxel里面,所有的數據都沒有一個像點一樣的ID來確定當前voxel里面的值是從哪轉移來的。解算出來的rest在一定程度上可以充當這個ID,但是也不是絕對的穩定,這也是為什么pyro solver里面會有一個rest2來當替補融合rest。另一種方法就是從volume中附帶的vel速度來估計其它值是怎樣轉移的,但畢竟幀與幀之間我們只能以線性勻速來估計,但是解算的時候速度肯定不是線性的而且大部分時間也不是均勻的。