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

 

posted @ 2015-12-03 16:37  鹏_VFX  阅读(11940)  评论(0编辑  收藏  举报