Houdini VEX 學習筆記 ( 一)


//VOP

 

//Wrangle

1 vector  min;
2 vector  max;
3 getbbox(min,max);
4 float   thetamax = 4;
5 matrix3 matrix_ini  = {{1,0,0},{0,1,0},{0,0,1}};
6 float   rotAngel = fit(@P.y,min.y,max.y,0,1);
7 
8 rotate(matrix_ini,rotAngel*thetamax,{0,1,0});
9 @P  = @P * matrix_ini ;

 //Define a label deftype ,  a tab Bend , deftype is a menulist

1 #pragma   label  deftype  "Operation"
2 #pragma   label  offset     "Offset Value"
3 #pragma  group XFORM    offset  deftype
4 
5 #pragma  choice  deftype  “0”  “Bend"
6 #pragma  choice  deftype  "1"  "Twist"
7 #pragma  choice  deftype  "2"  "Taper"

 // houdinivex 中的一個小片段,比較有用,摘抄下來

//會以當前點為基准,查找最近的10個點的速度,最后更新加速度

 1 float  max_radius      = 99999;
 2 int    max_neighbours  = 10;
 3 int    handle          = pcopen(@OpInput1,"P",@P,max_radius,max_neighbours+1);  //因為我們查找的是第一輸入端(@OpInput1),所以會把自己算進去。因此需要11個點  4 
 5 int    near_pt;
 6 int    near_count = 0;
 7 vector near_v;
 8 vector accum_v = {0,0,0};
 9 while( pciterate(handle))
10 {
11     pcimport(handle,"point.number",near_pt);   //如果是自己,就跳過 12     if( near_pt == @ptnum )
13         continue;
14         
15     pcimport(handle,"v",near_v);
16     accum_v += near_v;
17     near_count++;   
18 }
19 if(near_count != 0)
20 {
21     accum_v /= (float)near_count;
22     v@accel += (accum_v - @v) * 0.4 ;
23 }

// houdini 中使用copy節點進行模型替代粒子時,會遇到這樣的問題,可以設置N為速度的方向,但是up方向不好確定(不能一直是{0,1,0}),下面是一個簡單的方法

1 v@N     = normalize(@v);
2 v@up    = {0,1,0};
3 v@side  = normalize(cross(@N,@up));
4 v@up    = normalize(cross(@N,@side));  //side跟N是正交的,可以求出side后,利用它得到新的up

 //如何求出兩個向量a,b之間的夾角,並且判斷b是在a的左邊,還是右邊,下面摘抄的代碼簡單的實現了這一個效果

//  a = {0,1,0}     b = {1,2,0}   b可以隨機,只要在xy平面上

 1 // 返回 a b 之間的夾角, 0 到 pi
 2 float angle_between(vector a; vector b) {
 3     return acos(dot(normalize(a), normalize(b)));
 4 }
 5 // 2d  xy 平面  6 // b在a左邊,返回 -1 ; b在a右邊,返回1。觀察方向是從Z軸負方向。
 7 int left_or_right(vector a; vector b) {
 8     vector cp = normalize(cross(normalize(a), normalize(b)));
 9     if (cp.z < 0)
10         return 1;
11     else
12         return -1;
13 }
14 vector a = point(0, "P", 1) - point(0, "P", 0);
15 vector b = point(1, "P", 1) - point(1, "P", 0);
16 float ang = angle_between(a, b);
17 int d = left_or_right(a, b);
18 if (d == -1) {
19     printf("direction: left\n");
20     printf("degrees  : %d\n", degrees(ang));
21 }else {
22     printf("direction: right\n");
23     printf("degrees:   %d\n", degrees(ang));
24 }

//  學習VEX時整理的一個snippet, 代碼實現了Noise的全部功能

 1 float turb_noise(vector sample_point;    //采樣點  2                  vector frequency;       // 頻率  3                  vector offset;          // 偏移  4                  float  roughness;       // 當前這一層noise的值的倍數,用於加到累積和中。  5                  float  lacunarity;      // 每加一層noise,在計算下一層noise時會把頻率乘lacunarity  6                  int    octaves;         // 多少層noise   7                  float  exponent)        // 倍增,可以平滑曲線(把直線平滑成曲線)  8 {
 9     float sum = 0;
10     float weight = 1.0;
11     vector samp_p = sample_point * frequency + offset;
12     
13     for(int i = 0; i<octaves+1; i++)
14     {
15         sum += pow(noise(samp_p),exponent) * weight *4;
16         samp_p *= lacunarity;
17         weight *= roughness;
18     }
19 return sum;
20 }
21 vector frequency = chv("frequence");
22 vector offset    = chv("offset");
23 float  roughness = chf("roughness");
24 float  lacunarity= chf("lacunarity");
25 int    octaves   = chi("octaves");
26 float  exponent  = chf("exponent");
27 float  scale     = chf("scale");
28 float value = turb_noise(@P,frequency,offset,roughness,lacunarity,octaves,exponent);
29 @P.y += value;

在Houdini中得到的效果如下:

Vex 中利用通配符判斷點在多個組內

在vex中沒有函數pointgroupmask,注:某一個指定組時可用inpointgroup,這里討論的是多個組可以在wrangle中新建一個string 類型,利用表達式函數pointgroupmask函數表達式選出組,wrangle中代碼如下:

 

1 int result = 0; 2 string chosengroups[] = split( chs("maskparm") ); 3 foreach(string group;chosengroups) 4 { 5   result = inpointgroup(0,group,@ptnum); 6 }

 Vex 中引用全局變量

使用$符號

1 float nf = `$NFRAMES`;
2 printf("%s\n",nf);

 返回幀數:

240

 利用Vex后期加點

在做特效的時候經常要用一些曲線輔助,有時候曲線是之前調過的(一堆transform,edit節點飄過),只想在后面加點,下面vex可以幫助我們做到這些

注:已經把它升級為houdini shelf 工具,更方便 ,見帖:http://www.cnblogs.com/peng-vfx/p/5193750.html

1 int pt = addpoint(geoself(),vector( point(geoself(),"P",npoints(geoself())-1) ) + set(0,0,0.1)   );
2 int vt = addvertex(geoself(),0,pt);

下面圖片是前后對照:

             

 

 粒子沿曲線運動

 

 實現了Boids Behavior 的 Separation、Alignment、Cohersion這三個基本功能后(http://www.red3d.com/cwr/boids/),根據一些藝術效果可能需要集群沿着曲線運動,Houdini 中有popcurveforce節點,個人感覺用起來不方便,自己寫了一段vex,個人感覺用起來挺順手。

 1 float min_dist = ch("min_dist"); // 參數最小距離
 2 float max_dist = ch("max_dist"); //參數最大距離
 3 int handle;
 4 //near point on curve
 5 int index = 0;
 6 int old_index = i@init_goal;    //記錄單個個體追尋的曲線上點的序號
 7 //curve length
 8 float curve_length = 0;
 9 v@steer_before = v@steer_cur;
10 handle = pcopen(1,"P",@P,10000,30);
11 vector steer_attract = set(0,0,0);
12 vector steer_dir = set(0,0,0);
13 int near_pt = i@init_goal;
14 int sum = 0;
15 if(pcnumfound(handle)>0 )
16 { 
17    while(pciterate(handle))
18    {  
19        int source_curve = 0;
20        pcimport(handle,"curve_id", index);
21        pcimport(handle,"source_curve",source_curve);     //提取曲線的id
22        pcimport(handle,"N",steer_attract);
23        pcimport(handle,"P",steer_dir);
24        pcimport(handle,"sum",sum);
25        pcimport(handle,"perimeter",curve_length);
26        //if(index >= i@init_goal && (index-near_pt<3.6))
27        if((index > i@init_goal) && (i@source_curve==source_curve) )      //是集群沿着曲線往前走 , 用i@source_curve記錄追隨那條曲線id
28        {
29            if(index - near_pt <=3)  //每個substep不能走超過3個點
30            {
31             //near_pt = index;    
32             //steer_dir = normalize(steer_dir - @P)* fit(length(steer_dir - @P),0,1,0,10); 
33             i@init_goal = index;
34             break;
35             }               
36        }
37        else
38             continue;
39    }   
40 }
41 //found no points                  //如果沒有發現點,執行下面代碼
42 if(@init_goal<= old_index) 
43 {
44   @init_goal+=1;
45   int num_pt = findattribvalcount(1,"point","curve_id",@init_goal);
46   for(int i=0;i<num_pt;i++)
47   {
48   int temp_pt = findattribval(1,"point","curve_id",@init_goal,i);
49   int source_cur = point(1,"source_curve",temp_pt);
50   if(source_cur == i@source_curve)
51   {
52      steer_dir = point(1,"P",temp_pt);
53      steer_attract = point(1,"N",temp_pt);
54      break;
55   }
56   }
57 }
58 v@steer_r = steer_dir;
59 /** 下面if這段代碼不需要60 if(@Frame>6)
61 {
62     steer_dir += (rand(@id*7.4)-0.5)*0.003*{0,1,0}*index;
63 }
64 ***/
65 vector dir = (steer_dir - @P)*( float(index)/sum );
66 float curve_ratio = float(index)/sum ;
67 vector f1= normalize(dir)*chf("strength")*(rand(@id*6.7)*0.6+0.4);
68 vector f2= normalize(steer_attract)*chf("strength")*(rand(@id*6.7)*0.6+0.4)*(curve_ratio*0.5+0.8);
69 //v@steer_attract = lerp(f1,f2,fit(curve_ratio,0,0.25,0,1));
70 v@steer_attract = lerp(f1*14,f2*70,fit(length(steer_dir-@P),0.08,0,0,1));
71 v@steer_attract *= (rand(@id*104.6)+0.01);

 


免責聲明!

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



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