Houdini中角色通用修穿插方法


公司特效組最近一半的人一直都在做着修穿插這樣的一個重復的事情,聽說來公司之前大家也都一直這樣做着,這種完全不能把藝術家從重復勞動中解放出來的狀態確實有點讓人神傷。最近本人也在做着這方面工作,想借着這個機會,總結一下自己這方面的經驗,也重點探討一個能夠適用常規多數角色穿插問題的解決方法。希望能做到拋磚引玉的效果。

首先聊一聊角色動畫中常見的兩種穿插情況。

第一種比較常見的是角色與其他物體的穿插,比如手拿杯子腳踩地。這種情況的解決方法比較靈活,因為是兩個物體,所以常常可以使用volume的那套方法找到穿插的位置在用gradient或者ray的方法解決穿插的問題。另外這種情況往往我們可以很清楚的定義穿插面和被穿插面,兩個雖然理論上是相互影響的,但是處理起來我們完全可以忽略掉被穿插面(被角色碰到的區域)的變形問題,因為大多情況是根本不用變形,所以變形的變數是很好控制的。

還有另一種情況的角色穿插就是由於前端rigging流程沒有做到百分中百的角色防穿插或者類似自己的手拂動自身的肉這種情況,首先我們是在一個solid surface上找到不同的面之間的穿插,如果引入volume的那套方法就意味着我們要依靠人為的判斷,手動的在穿插之間的地方將角色砍開,在分別做處理。這種方法無疑是離不開重復勞動,而且如果穿插位置有好幾處的話,大概拿到鏡頭的人就只會想怎么cheat了。

 

估計如果大家真有在houdini里面修穿插的經歷后基本上都會了解怎么使用volume和ray來處理了。我這里只想重點聊一聊第二種情況下,如何程序化的搞定穿插問題。

解放藝術家的雙手,讓他們去做更有創造力的事情。  -- 機器貓

 

先看一看效果:

變形前

變形后

先講一講思路,再一個一個細聊:

1,使用intersect方法找到交叉位置

2,將穿插位置的法相方向統一

3,用新的法線在找出來的區域重新做一次intersect得到較准確的擠壓偏移量displacement

4,找出交叉區域露在外面的邊緣

5,柔化外邊緣后根據法線和邊緣權重向外擠出一點budge

6,統一給穿插以及邊緣部位做平滑smooth

 

在整個過程中因為測試的幾何體細分程度有比較大的不同,發現直接使用原mesh上的點做上面的采樣與計算,結果是非常不穩定的,而且最后的動畫穿插部位會有很嚴重的抖動問題。因為隨着動畫的運動,穿插部位的點進入穿插和離開穿插區域都會對之后的變形產生比較明顯的影響,說白了就是采樣點不夠密。所以在這個討論的改進版本中,使用了scatter給物體撒點來采樣的方法。散的點密度越高,面片抖動的問題就會越小。這個方法要求的就是scatter撒的點在動畫過程中相對位置是固定在mesh上的,這個使用uv的方法是不難實現的。

 

1,使用intersect方法找到交叉位置

用撒完的點雲在三角面片化的mesh上進行一次intersect計算。判斷穿插與未穿插其實也不難,如果我們沿着向外的法線去求解的話,如果碰到自己mesh的次數是奇數次的話那就說明這個點是在幾何體的內部,如果是偶數次的話則說明是沒有穿插的點。道理自己想。

值得一提的是如果使用intersect這個功能的話,碰撞的到的prim的法線方向與入射的法線方向接近90度的話是非常容易對下一次迭代的計算長生干擾而出現錯誤的。這種情況類似於入射的法線切過曲面表面。在這里我使用的是向量點乘的方法避開這種比較敏感的情況。另外針對於穿插的區域以及邊緣區域,我在整個過程中使用的紅色來代表的,這樣可視化的程度也高一點。

這個可能算是這個方法里面最重要的一步了,就是用它找到了自身穿插的部位。

 1 vector startPos = @P + normalize(@N) * 0.00001;
 2 
 3 vector rayDir = normalize(@N) * 100;
 4 
 5 vector collidPos;
 6 float myu, myv;
 7 int flag = 1;
 8 int count = 0;
 9 
10 while(flag){
11         int primNum = 0;
12 
13         primNum = intersect(1, startPos, rayDir, collidPos, myu, myv);
14 
15         if(primNum != -1){
16             //i@primNum = primNum;
17             vector primNor = prim(1, "N", primNum);
18             //v@primNor = primNor;
19 
20             if(dot(normalize(primNor),normalize(@N)) > 0.05){
21                 startPos = collidPos + 0.00001 * normalize(@N);
22                 count++;
23             }else{
24                 break;
25                 }            
26         }else{
27             break;
28         }
29 }
30 
31 if(count % 2  != 0){
32 
33     @Cd = set(1,0,0);
34 }else{
35     @Cd = set(0,0,0);
36 }

2,將穿插位置的法相方向統一

這個步奏就稍稍需要一點技巧了,統一或者模糊任何一個屬性的話是需要與相鄰的點進行平均。而穿插的問題就是不同法相的點已經攪合在一起了,所以使用穿插狀態的點雲來統一法相,效果會適得其反。這里我們就需要引入T pos模型了,做動畫的肯定會有T pos這個狀態的模型給你調用的。

解決法相統一的問題是為了之后沿着新的法相做偏移做准備的。因為穿插的部位往往是具有弧度的曲面,那么在擠出穿插部分時,如果使用原來的法相,有可能會出現擠出后點變得混亂。如圖:

雖然上面示意的可能有點極端,但是這就是為什么我們不推薦使用原來的法相來進行擠出了。

這里說到的統一其實也是沒有達到絕對意義上的一致,只是讓法線與相鄰點的法線更加有相關性。

 

3,用新的法線在找出來的區域重新做一次intersect得到較准確的擠壓偏移量displacement

有了第一步做准備,這一步就沒什么門檻了,再重復一次intersect,只不過這次只是在之前被檢測的區域內反向進行計算。

 

4:找出交叉區域露在外面的邊緣

這里我們使用的方法是根據原來檢測出來的區域范圍使用pcfilter的方法把選區擴大,當然filter會改變已有選取的值而且邊緣也是漸變模糊的,我們直接使用大於0的判斷重新把值變為1就好了。在用這個擴大了的選區減去之前的選區就得到了圍繞穿插位置的一個圈圈選區了。這個過程用到了點雲計算所以依舊是挪到T pos下面做的處理。

 

5,柔化外邊緣后根據法線和邊緣權重向外擠出一點budge

這一步沒什么好講的了,就是把上一步的選區柔化一下,然后當做權重值來擠出穿插的邊緣區域,讓碰撞的地方更有肉感一點。

 

6,統一給穿插以及邊緣部位做平滑smooth

這里可以直接使用smooth節點,或者再之前使用neighbours找出鄰居點並平均鄰居點位置來確定自己的位置,這樣能夠更平滑一點。

 

終結一下,這個方法能完善的地方其實還有很多,比如如何然穿插偏移量更精確,以及讓scatter點分布更均勻。尤其是scatter這個環節,H14上的scatter能夠均勻分布了,但之前了解到的這種通過迭代來均勻分布的方法也不能100%的保證點雲能夠完全跟着動畫mesh走。這些方面再以后有機會了慢慢完善吧。 

最后是這個方法的一個文件,大家可以參考一下,也很希望得到意見與反饋。

修穿插源文件


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM