Houdini VEX 学习笔记 (二)

时间:2024-04-16 21:28:01

//利用属性分开Primitive

Primitive Split 节点中Attribute 设置为split 。Wrangle中代码为:    f@split = @ptnum>10?1:4;

比较程序化的是利用Houdini 的Paint 节点,给物体描绘上颜色,然后利用颜色属性把Primitive 分开


//曲线(在Vex中实现Carve节点的功能)

最近在做植物生长的rnd,期间生成了大量的curve,急需有能有个类似Carve节点的vex 函数,发现Vimeo上有大神用vex实现了这个功能(https://vimeo.com/104891696),后来在Odforce上看到,其实Houdini的Include文件中,有一个函数adjustPrimLength(在$HFS/houdini/vex/include/groom.h文件中定义)实现了这个功能,写的极其简洁,很美。具体代码如下:

void adjustPrimLength(const int geo, prim; const float currentlength, targetlength)
{
    float diff = targetlength - currentlength;
    int points[] = primpoints(geo, prim);
    if(diff > 0)
    {
        vector posA = point(geo, "P", points[-2]);
        vector posB = point(geo, "P", points[-1]);
        vector posC = diff * normalize(posB-posA) + posB;
        int ptnum = addpoint(geo, posC);
        addvertex(geo, prim, ptnum);
    }
    else if(diff < 0)
    {
        vector lastpos = 0;
        float length = 0;
        int cut = 0;
        foreach(int idx; int pt; points)
        {
            vector pos = point(geo, "P", pt);
            if(idx > 0 && !cut)
            {
                float seglength = distance(pos, lastpos);
                if(length+seglength > targetlength)
                {
                    float frac = (targetlength-length)/seglength;
                    vector newpos = lerp(lastpos, pos, frac);
                    int ptnum = addpoint(geo, newpos);
                    for(int i=idx; i<len(points); i++)
                        removepoint(geo, points[i]);
                    addvertex(geo, prim, ptnum);
                    break;
                }
                length += seglength;
            }
            lastpos = pos;
        }
    }
}

在Houdini中的使用如下,首先每条Curve需要有一个属性 @perimeter,记录曲线的长度,这个属性可以由Measure节点实现(Type设成Perimeter,Attribute设成perimeter)。然后下面接一个primitive wrangle 节点(Run Over设成Primitives),里面代码如下:

#include <groom.h>
adjustPrimLength(0, @primnum, @perimeter, @perimeter*chf("dist"));

前后对比如下:

 实际应用中,应该把dist也设置成属性,来更方便的控制:adjustPrimLength(0, @primnum, @perimeter, @perimeter*@dist);

//Pack 物体 ,传递Name属性

利用pack 节点pack 物体后,把name从原来的primitive传递到point

s@name = primintrinsic(0, "fragmentname", @primnum);

 //VEX 隐藏属性: primive的P属性

新建一个Grid, 下面接一个point wrangle ,代码如下:

@P = prim(0,"P",@primnum);

 再接一个 delete , 删掉primitive,保留点,把之前的Grid template 显示,可以看到点移到primitive 的中心去了,不过如果两个面共享一个点时,这时这个点会跑到一个面的中心,但是对于Pack物体来说,就无所谓了,一个Primitive就对应一个点

 // Cone Twist Contraint 的配置

Primitive Wrangle

s@constraint_name = "cone";
s@constraint_type = "all";
v@constrained_twist_axis = @N;
v@constrained_up_axis = set(0,1,0);
v@goal_twist_axis = @N;
v@goal_up_axis = set(0,1,0);

 // 两点组成的曲线

primitive wrangle

int pointindex(int prim; int vtx)
{
    return vertexpoint(geoself(), vertexindex(geoself(), prim, vtx));
}
int pt0 = pointindex(@primnum, 0);
int pt1 = pointindex(@primnum, 1);

f@restlength = distance(pt0,pt1);

  // 临界边

比较有意思,实现起来其实不难,想法比较好。先把Surface碎开,如下图左。然后用Divide节点,勾选 Remove Shared Edges,图中。

       

然后,Wrangle如下,把边上的点删掉,只留顶点,最后用Convertline转成线,就得到一个简单的邻边。

if(len(nearpoints(0,@P,0.0001))<3)
{
    removepoint(geoself(),@ptnum);
}