
//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);
