龍卷風的實驗斷斷續續持續了較長一段時間,主要是想通過這個方式把流體的速度場和力場好好磨一磨,之前一直覺得流體的形態可控性不高,所以希望能找到一些方法或者經驗能夠摸透流體的運動。
說到龍卷風大家都不陌生,在特效圈子里面也是一個非常經典的案例,做好龍卷風能一定程度上體現出一個特效師在多個方面綜合的素質體現。現在市面上的方法確實不少,各種軟件在龍卷風的時候也有各種不一樣的特性體現,但最終表現大多都離不開流體和粒子這兩種。今天我就梳理一下,通過流體和速度場搭建龍卷風效果的不同方法和橫向的效果比較。
在講應用之前還是先從龍卷風講起,這段時間也是查了不少資料。其中比較有用的就是下面的幾張圖,以及在國外網站上找到的一個研究生的畢業論文。這個學生也是想用houdini做一個可控的龍卷風,但是全片下來除了把現有的龍卷風類型講的比較透徹,在應用那一塊基本上也可以直接忽略了,可想國外的研究生有些過得也是比較水的。
第二張圖是從wiki的vorticity中截取的,這個截面比較直觀的體現了龍卷風風場橫截面的速度與中心的關系了。
原理搞懂后不難得出,龍卷風的運動特性是渦流的一種體現,很多時候飛機引擎的前后也能出現類似小旋風的情況也就是這個道理。所以在houdini中應用主要就是看怎樣認為的形成類似渦流的速度場。
1:先講第一個方法
這個方法也是沿用的國外某個教程的方法,簡單明了,也適合很多人的理解,下面是速度場的骨架:
這個方法主要是利用了龍卷風具有螺旋線的運動特征,所以最直觀的搭建了這樣的骨架,但是流體通過這個表現出來還是會有一些些的小瑕疵,那就是幾個螺旋線都是最后變成管道的,而管道與管道之間就會形成B一樣的外形凹槽,這個槽有可能會在流體的運動中體現出來而出現類似螺絲釘的樣子。這個有好也有壞,如果把點雲擾亂了,這種效果就不會那么明顯了。
這是用這個方法生成的一版效果,精度比較低,筆記本就是爛,湊合看吧。
2,第二種方法完全是自己試探性的玩法,也就是幾個平行的管道加一點惱亂形成的平行高速運轉的旋風效果,這個方法可以使用在已經穩定的龍卷風身上。
這個方法能讓流體在速度場類非常穩定的跟着擾動的變化而更改位置,效果還不錯,能夠適用在比較魔幻的效果里面。
下圖的這個效果應為把turbulence加大了一點,結果就像有妖氣了一樣:
再來張福利:
3,第三種方法是直接使用一個運動軌跡的外殼來確定速度場方向的,這個連續性比較強,而且運動的外觀也類似第一個方法那樣可控性比較強。
效果圖:
4,第四個方法,我本來以為是應該最好的方法,因為是用程序寫的力場,速度渦輪和大小都非常類似真是物理中的樣子,而且是整個box里面都充斥這非常精准的速度值。但是效果不盡人意,也許是我深挖的不夠,目前來說就是效果趣味性不強,也許我加大擾亂場可能會有很大改觀,這里我就不再做這個測試了。所有類型的工程文件都在文章最后,有時間點朋友可以拿着繼續測試下去,也很歡迎有更好的結果出現。
程序是在vex里面寫的,整體來說不難,得出的矢量場也感覺沒太多問題,也許就是太沒問題太規則了 :P
1 float worldScale = chf("worldScale"); 2 float curlExp = chf("curlExp"); 3 float lengthExp = chf("lengthExp"); 4 float upScale = chf("upScale"); 5 float upExp = chf("upExp"); 6 7 8 9 int handle = pcopen(1, "P", @P, 1e6, 1); 10 11 vector guidePos = set(0,0,0); 12 float radius = 0; 13 14 //get skeleton guide position and radius values 15 while(pciterate(handle)){ 16 pcimport(handle, "P", guidePos); 17 pcimport(handle, "radius", radius); 18 } 19 20 //get the curl direction 21 float distance = length(guidePos - @P); 22 23 vector front = set(0,0,0); 24 if(distance > radius){ 25 front = normalize(guidePos - @P); 26 } 27 vector up = set(0,1,0); 28 vector right = cross(front, up); 29 30 //define the curl bias from the edge to the center 31 vector minBox, maxBox; 32 getbbox(geoself(), minBox, maxBox); 33 float maxRadius = min((maxBox.x - minBox.x),(maxBox.z - minBox.z))/2; 34 float centerWeight = fit(distance, radius, maxRadius, 0.95, 0.02); 35 36 float frontBias = pow(centerWeight, curlExp); 37 vector curlForce = lerp(front, right, frontBias); 38 39 //define the up direction vector 40 vector empty = set(0,0,0); 41 float upBias = pow(centerWeight, upExp); 42 vector upForce = set(0,0,0); 43 if(distance > radius){ 44 upForce = lerp(empty, up * upScale, upBias); 45 }else{ 46 upForce = @P - guidePos; 47 } 48 49 50 //combine all forces together 51 float lengthBias = pow(centerWeight, lengthExp); 52 vector mainForce = (curlForce + upForce) * lengthBias * worldScale; 53 54 @N = mainForce;
最后一個方法也許能夠用來物理模擬之類的吧,但是單看效果來說就是渣渣了。不過我還是固執的認為這只是暫時的,因為他的形態是最沒有人工痕跡的,之后再好好琢磨整一整應該也能出好的結果的。
聊了這么多,貼圖也貼累了。個人來講比較喜歡使用第二種和第三種方法。當然還有很多其他的方法是我沒有考慮到的,很明顯這篇博客就沒有包括粒子速度場,沒講的原因主要還是覺得粒子本來形態的可控性就沒有固定點雲的形態好控制,如果再使用粒子來驅動流體,簡直就是給自己找麻煩,所以這里我也直接忽略了。但是絕對不排除有大神直接玩得轉的。還有一個大方向是直接使用粒子來模擬,這篇文章講的是流體,所以這個方法也不在這講了。
前前后后這些實驗一共花了十天左右的空余時間,感覺還是挺值得的。也許上面所有的方法都還是有瑕疵,但是實驗的過程就是一種探明道路的過程,重點不是你走到哪了,而是自己知道怎么開路了。
接下來看有時間吧pyro里面的東西好好捋一下。所謂的可控性就是你知道程序在底下自己在干嘛,千萬別被他一堆一堆的參數給蒙住了。
看到這,你就可以接源文件了 :P