
Q:為什么要用程序化制作水珠?動力學(xué)解算不香嗎?
A:動力學(xué)解算雖然直接但是太過于浪費資源,且結(jié)果不夠直觀,需要解算N多幀才能獲得結(jié)果,而且結(jié)果不穩(wěn)定,實際工作中通常采用程序建模配合少量動力學(xué)解算達到掛水效果。
國際慣例先導(dǎo)課
基本思路是在物體表面通過copy to point 來獲得基本的分布形態(tài),然后借助隨機的pscale來創(chuàng)建隨機的大小。由于水珠的上小下大的形態(tài),所以要在單個球形的基礎(chǔ)上沿著物體向上復(fù)制一個小球,通過vdb smooth 將一大一小兩個球算到一起,獲得水滴形體。
如何獲得點沿著面的方向向上的向量?
求得物體向上復(fù)制方向的過程中需要用到向量積,cross product。
首先用面上點的法向和{0,1,0}向量做向量積,獲得平行于面的橫向向量,然后用橫向向量和法向再做向量積,就可以獲得沿著面向上的向量。

注:向量積的計算遵循右手定則,即用cross(N, UP) 和cross(UP, N)獲得的是截然相反的向量。
正式課程
首先是在模型上散點,可以用scatter來隨機布點,當(dāng)然如果對視覺結(jié)果有了大概的規(guī)劃,也可以用spray paint 手動畫點(這個也是相對Dop Network的優(yōu)勢)。

注:這里建議只針對攝像機區(qū)域進行撒點操作,如果是針對整個模型后期計算量會比較大。
此時如果直接用copy to point 連接一個Sphere,就會獲得大小均一的復(fù)制。

顯然我們想要的是隨機化的大小,copy to point 可以接受全局變量pscale屬性,我們可以在PointVOP中使用噪波來隨機化pscale,從而達到隨機化復(fù)制大小的結(jié)果。

需要注意的是,采用aaNoise的默認(rèn)振幅會產(chǎn)生從-0.5到0.5區(qū)間的噪點,pscale理論上是不存在負值的,所以這里用fit先將aaNoise的結(jié)果映射到0-1內(nèi),然后用ramp parameter控制噪點分布。如果需要更大的噪波范圍可以再接一個fit用max來控制。
此時雖然從視口上并沒有任何變化,但是通過觀察geometry spreadsheet 可以發(fā)現(xiàn)每個點都多出了一個pscale屬性,這個屬性就可以作為copy to point 的復(fù)制比例參數(shù)。也就是 最終拷貝大小 = sphere本體大小 * pscale。

考慮到真實的水珠掛壁狀態(tài)是上小下大的,可以用一大一小類似葫蘆的兩個水珠通過VDB 做成一個水珠。

以目前拷貝的水珠為基礎(chǔ),此時沿著面向上平移一定距離再拷貝一個水珠,此時就用到了先導(dǎo)課里面的向量積運算。

小水珠向上的方向可以用向量積求出,entagma老哥這里用的PointVOP,這里我用了效率比較高的PointWrangle,首先自定義一個UP,用UP和N做向量積,得到平行向量。然后用平行向量和N繼續(xù)向量積,得到最終沿著平面向上的向量。再用normalize()函數(shù)規(guī)整到一個單位長度,再乘以一個自定義的因數(shù),就可以得到類似displace along normal的效果了。從這里也可以看出Displace along normal 背后的原理其實是:最終向量 = 向量 * 因數(shù)(此處為點乘),只不過在VOP中,我們把向量作為Normal的輸入來處理了。(這么說其實mountain也就是隨機的displace along normal)
vector UP = {0,1,0};
vector tan = cross(@N, UP);
vector nN = normalize(cross(tan, @N));
@pscale *= chf("top_scale");
自定義的因數(shù)應(yīng)該和上方水珠的大小有一定正相關(guān),才會讓水珠看起來比較合理。
剛好這里pscale是一個浮點數(shù),可以作為向量點乘因數(shù),上方水珠的距離 = 上方水珠的pscale * 最終向量 * 一個因數(shù),毫不猶豫past relative reference! 同時借助chf()自建一個因數(shù)來控制大小。
@P += nN * chf("distance_scale");
最終PointWrangle如下。

ok! 此時觀察結(jié)果可發(fā)現(xiàn)基本水珠形體已經(jīng)有了,但是真實的水珠是扁的,不會這么圓潤。這時可以借助另一個全局變量scale,默認(rèn)情況下scale的值為{1,1,1},通過如下語句重新設(shè)置scale在特定方向上的大小。
v@scale = set(1, 1, chf("Flat_ratio"));
注:一定要明確,object的Z軸正方向?qū)?yīng)的是copy后N的正方向,也就是通過Z方向的縮放來改變拷貝物體的大小。
Bug!

通過向量積獲得的點的位置有可能已經(jīng)飛出模型表面了!所以一定要檢查水珠出現(xiàn)位置的合理性!
出現(xiàn)這種問題也很好解決,返回到scatter節(jié)點,把可能出現(xiàn)問題的面取消選擇就好了。

接下來就是簡單的 VDB from polygon, VDB Smooth SDF 以及和模型本身轉(zhuǎn)化成的VDB進行布林運算。這里有幾點需要注意:
1.在多個節(jié)點中Voxel 大小需要統(tǒng)一且不宜太小,Voxel太小的會造成過大的運算壓力導(dǎo)致崩潰;
2.原模型如果是片體是無法轉(zhuǎn)化為VDB的,此時可以靈活使用polyfill節(jié)點,將模型轉(zhuǎn)化為實體;
2.VDB的計算參數(shù)設(shè)置好以后,及時使用fileCache可以避免后期運算壓力過大;

這里Voxel size設(shè)定為0.05,對計算有一定壓力,合理使用cache來緩沖壓力。同時在VDBreshape中可以適當(dāng)調(diào)節(jié)形態(tài)學(xué)計算方式,這在之前的文章中有提及。
至此建模任務(wù)就差最后一步。
想象一下由VDB轉(zhuǎn)化回來的面,表面一定是凹凸不平的,這樣和模型接觸的面也一定是會出現(xiàn)穿模,影響渲染引擎的法線判定,必然會產(chǎn)生錯誤。這時試想如果有一個參數(shù)能控制當(dāng)前幾何體到模型的距離就好了!有!
xyzdistance是一個檢測當(dāng)前點到目標(biāo)幾何體面距離的函數(shù),這里用PointVOP來更加明確。

xyzdistance返回的是距離當(dāng)前點最近的目標(biāo)幾何體上的primnum面序號和UV點在面上的投射位置,而primuv其實是prim attribute,這個節(jié)點的作用是計算當(dāng)前幾何體&&當(dāng)前面&&當(dāng)前UV的屬性值,默認(rèn)是Cd,改為N則計算當(dāng)前位置的法向,而當(dāng)前位置的法向剛好是我們作為幾何體縮放的依據(jù),Bingo!
毫不猶豫接入Displace Alone Normal,通過amount來控制收縮大小。
節(jié)點圖

此時已經(jīng)有了車的模型和水滴的模型,分別用objectMerge分入兩個Object方便賦材質(zhì)。

如何創(chuàng)建背景雨滴?
可以考慮用速度場對場內(nèi)的點產(chǎn)生的trail來作為模型生成的依據(jù),借助resample增加curve的點數(shù),同時添加curveu參數(shù)。

注:需要觀察點的序號,如果curveu的漸變和想要的數(shù)值漸變方向相反,則需要1-@curveu。


測試渲染發(fā)現(xiàn)redshift自帶的光圈圖太機械并不理想,索性手動進ps畫了一個。

調(diào)整一下構(gòu)圖,最終效果!
