原视频:https://www.youtube.com/playlist?list=PLzRzqTjuGIDhiXsP0hN3qBxAZ6lkVfGDI
Bili:Houdini最强VEX算法教程 - VEX for Algorithmic Design_哔哩哔哩_bilibili
Houdini版本:19.5
几何体的一些基本的固有属性,比如面积测量、体积测量、边界框(bounds)、封闭(closed-是否闭合填充面)、几何体id&类型、以及一些变换常用相关属性(Pack相关函数)。
感兴趣可以去看看官方文档。
图片及解释来自知乎@刘鹏云:内置属性与几何体类型和属性类别有关,内置属性只存在于primitive和detail 属性中, polygon\mesh \nurbs …不同的几何体类型,带有不同的内置属性。
内置属性(比如measuredaea)是已经计算好的值,可以直接读取。
相比使用measure节点重新计算面积,更节省计算机资源(感兴趣可以看第17节视频14分钟处的对比)。
eg.测量Sphere小球的面积,
操作:添加类型为Polygon的Sphere小球节点,添加并连接类型为Primitives的Attribute Wrangle节点,写入如下代码,
float area = primintrinsic(0, 'measuredarea', @primnum);
f@area = area;
结果:代码可获取内在属性—>面积measurearea,可打开内在属性对比面积值,值相等。
与【2、Primitive Intrinsic Attribute(measuredaea)面积测量】类似,不过多一个节点(attribpromote)计算总体积(方法也可以计算总面积)。
eg.测量Sphere小球体积,按下图添加节点(attripromote节点稍后设置),
设置:
sphere类型为Polygon,measuredvolume节点类型为Primitives,写入代码,
float volume = primintrinsic(0, 'measuredvolume', @primnum);
f@volume = volume;
结果:对attripromote节点进行设置,用它来测量总体积,
(也可以使用measure节点直接测量体积‘总体积)
Polygon和PolyMesh有边界框属性。
eg.①创建类型为polygon的sphere小球,添加连接delete1节点,仅保留一个面,
结果为:打开内在属性bounds,
②继续操作:先上节点图及结果,结果为线框显示模式,
③节点设置:
在类型为Primitives的prim_bounds节点写入如下代码,
float bounds[] = primintrinsic(0, 'bounds', @primnum); //读取bounds属性内的坐标值
float minx = bounds[0];
float maxx = bounds[1];
float miny = bounds[2];
float maxy = bounds[3];
float minz = bounds[4];
float maxz = bounds[5];
vector minpos = set(minx, miny, minz);
vector maxpos = set(maxx, maxy, maxz);
vector size = maxpos - minpos; //缩放值。比如矩形的长度(X坐标值),X的max坐标值减去min坐标值,即可得到长度
vector cenpos = (minpos + maxpos) * 0.5; //边界框中心点
int pt = addpoint(0, cenpos); //中心点创建点
setpointattrib(0, 'scale', pt, size); //对该点进行缩放
setpointgroup(0, 'center', pt, 1); //把某个对象/组移动到该点上
④copytopoints1节点的Target Points设置为center。
使用类型为polygon/polygonMesh的几何对象,表格切换到Detail表格值,打开内在属性bounds,这个表示的是整个几何体的边界框,
eg.与【4、Primitive Intrinsic Attributr(bounds)边界框】类似。
②设置:
Sphere类型为Polygon,
在类型为Primitives的detail_bounds节点写入如下代码,
float bounds[] = detailintrinsic(0, 'bounds'); //读取bounds属性内的坐标值
float minx = bounds[0];
float maxx = bounds[1];
float miny = bounds[2];
float maxy = bounds[3];
float minz = bounds[4];
float maxz = bounds[5];
vector minpos = set(minx, miny, minz);
vector maxpos = set(maxx, maxy, maxz);
vector size = maxpos - minpos; //缩放值。比如矩形的长度(X坐标值),X的max坐标值减去min坐标值,即可得到长度
vector cenpos = (minpos + maxpos) * 0.5; //边界框中心点
int pt = addpoint(0, cenpos); //中心点创建点
setpointattrib(0, 'scale', pt, size); //对该点进行缩放
setpointgroup(0, 'center', pt, 1); //把某个对象/组移动到该点上
③copytopoints1节点的Target Points设置为center
closed属性,大概就是面是否填充的意思,其值可读写,值为0或1。
直接使用几何体及primitive节点设置closed属性。打开表格内打开内在属性closed,观察变化,
eg.创建一个类型为polygon的sphere节点,添加及连接一个类型为Primitives的AttributeWrangle节点,并写入如下代码,
float rnd = rand(@P);
if(rnd < 0.75){
setprimintrinsic(0, 'closed', @primnum, 0);
}
//也可以在上右图中间添加PrimitiveWrangle节点; 结合使用 setpointgroup()函数,对需要设置的closed值设组; 再结合上右图的primitive节点进行组设置,也可达到同样的效果
eg.先上节点图及结果,表格中打开内在属性 tyoeid、typename,
操作:在类型为Points中写入如下代码,
int prims[] = pointprims(0, @ptnum); //合并后,在merge节点仅有3个primitive/对象
int prim = prims[0];
int typeid = primintrinsic(0, 'typeid', prim); //获取几何体类型的id
if(typeid == 1){
setprimattrib(0, 'Cd', prim, set(1, 0, 0)); //条件符合,设为红色
}
8、Intrinsic Attribute for Packed Geometry打包几何体
Pack Primitives:对图元进行打包,打包后,作为一个模板几何体来使用,需要的时候可以直接引用。无需复制那样,生成一个又一个占用内存的副本。(粗暴理解:复制文件与创建快捷方式)
packed geometry 中常用内在属性为轴点pivot、变换transform。(轴点与中心点不同,轴点与旋转、缩放相关)
也有缺点,打包后,仅能使用一些固有Pack属性(位移旋转缩放)等,不能访问原几何体的属性。
一些打包类型:
①In-memory packed primitives几何体们打包到的内存、
②Packed disk primitives打包到磁盘、
③Packed Disk Sequence primitives打包序列帧到磁盘:个人理解,在Houdini中,每一帧图像都会生成一个文件,这会消耗大量时间并且不利于管理。而Packed Disk Sequence可以将所有帧图像打包成一个单独的文件,其中每一帧都可以通过整数索引进行访问。例如,一个Packed Disk Sequence文件"myseq0001.ext"中的第3帧图像可以通过"myseq0001.ext[2]"来访问。这种方式可以大大提高文件读取和访问速度,并且方便进行网络传输和版本控制。
⑤Packed fragments打包片段(按命名打包,后面练习细说)。
【可以去看看官方文档解释及知乎的翻译】
eg.对打包后的对象进行旋转、缩放、位移等变换,主要使用packedtransform() 函数,或setpackedtransform()函数,它俩都可以实现同样结果。packedtransform()函数从轴点开始旋转缩放,setpackedtransform()函数从(0.,0,0)开始旋转缩放。
操作:
①创捷一个rubbertoy节点,添加并连接一个pack节点,观察打包后其节点信息变化,
②在下方添加一个类型为Primitives的AttributeWrangle节点,并写入代码,(视频有更详细的函数讲解,感兴趣可以看第17节53m~1h11m部分),
vector dir = set(-chf('x'), 0.0, 0.0); //移动距离
vector pivot = primintrinsic(0, 'pivot', @primnum); //获取轴点
float ang = chf('ang') * $PI * 2.0; //旋转角度
float s = chf('scale'); //缩放
matrix mat = ident(); //单位矩阵,值为1
//使用 packedtransform()函数时,需要加这一行代码
//translate(mat, -pivot); //把中心点移到原点(0,0,0),否则旋转、缩放时会奇奇怪怪
scale(mat, set(s,s,s));
translate(mat, dir);
rotate(mat, ang, set(0, 1, 0));
translate(mat, pivot); //把中心点又移回去
//因为setpackedtransform()函数已把中心点定义为(0, 0, 0),所以无须把中心点移动到原点(0,0,0)
setpackedtransform(0, @primnum, mat); //对打包后的对象进行变换
//packedtransform(0, @primnum, mat); //使用该函数,需加多一行代码
结果:略(gif图好像有点问题,上不了动,很烦)
eg.①先对上一个案例【8、Intrinsic Attribute for Packed Geometry打包几何体】的变换矩阵进行存储,在最后一行添加一行代码,
4@mat = mat; //仅方便后面作对比
②添加一个类型为Primitives的AttributeWrangle节点,写入代码,
matrix mat = getpackedtransform(0, @primnum);
做一个类爆炸的东东。
eg.①先上节点图,其中Pack按图设置,可把对象按照名字进行打包,
③在类型为Primitives的explosion节点写入代码,
float f = (@Frame - 1.0) / $FEND;
vector pivot = primintrinsic(0, 'pivot', @primnum);
matrix mat = ident();
translate(mat, -pivot); //把打包后的对象,中心点移到到原点
packedtransform(0, @primnum, mat);
④对代码进行修改,使碎片绕自身旋转,
float f = (@Frame - 1.0) / $FEND;
vector pivot = primintrinsic(0, 'pivot', @primnum);
matrix mat = ident();
translate(mat, -pivot);
rotate(mat, f * chi('ang') * $PI, normalize(sample_sphere_uniform(rand(@P)))); //随机生成同一个向量
translate(mat, pivot);
packedtransform(0, @primnum, mat);
结果为:ang=2条件下,物体原地旋转,
⑤继续修改代码,使其旋转的同时,向外飞,
float f = (@Frame - 1.0) / $FEND;
vector pivot = primintrinsic(0, 'pivot', @primnum);
matrix mat = ident();
translate(mat, -pivot);
rotate(mat, f * chi('ang') * $PI, normalize(sample_sphere_uniform(rand(@P)))); //随机生成同一个向量
translate(mat, pivot);
//旋转的同时,向外移动随机距离,移动方向位原点——>轴点方向
float mult = fit(rand(@P + 3.52), 0.0, 1.0, 0.2, 1.0);
vector dir = normalize(pivot) * chi('dist') * f * mult;
translate(mat, dir);
packedtransform(0, @primnum, mat);