原视频:https://www.youtube.com/playlist?list=PLzRzqTjuGIDhiXsP0hN3qBxAZ6lkVfGDI
Bili:Houdini最强VEX算法教程 - VEX for Algorithmic Design_哔哩哔哩_bilibili
Houdini版本:19.5
1、什么是Volume?
以下说明主要来自_burn博主:
Houdini支持两种体积类型,它自己的体积格式(也就是Volume,有两种)和VDB格式。
Volume的两种类型:Fog volume和SDF volume。是Houdini自带的不同类型的体积,特点是每个体素都有值。
Fog volume实际是储存了每个体素的密度,应用于流体模拟等。(本节主角)
SDF volume中(SDF Signed Distance Filed 是带符号的距离场),每个体素存储了一个数值,数的值表示到表面的距离,正数代表在物体外,负数代表在物体内,0表示在物体表面(需要精度较高)。所以将几何体转化为碰撞物的时候,实质就是转化为SDF,利用体素的数值来判断是否发生碰撞。详细请后面的第23节笔记
Volume(体积)由voxel(体积元素,后面简称为体素)组成,就像polygon(面)是由point(点)组成。一个volume(盒子)可以被细分为很多小voxel(盒子)。
体素voxel类型:scalar(标量),vector,matrix矩阵
一个voxel只有一个scalar,是从单个方向的。要存储方向又要存储密度,所以用3个scalar来存储数据,也可以称它为向量VectorVolume。不懂点这。
2、标量ScalarVolume设置与可视化
可视化又可显示为:颜色可视化、表面可视化。
eg.可视化为颜色
创建一个Volume1节点,设置为:Rank:Scalar标量、Name:density(方便后面脚本引用)、InitialValue:1(密度为1,密度为0,节点不可见)(标量类型只需填第一个)、UniformSamplingDivs:50(把Volume1细分为50*50*50):
添加连接一个volumevisualization1可视化节点,对节点设置如下
可视化节点的渐变色块对应Volume1节点的初始密度值InitialValue(0~1),所以当前Volume1在场景中的颜色为红色。
在上面两个节点中间添加一个VolumeWrangle节点(density),写入下面代码:
f@density = chf('d');
即可通过滑动数值控制Volume1的颜色。
修改VolumeWrangle节点(density)代码,通过随机函数 noise() 设置voluem1不同密度值:
f@density = noise(@P*2);
// noise() 随机函数,返回值0.3~0.7
// @P 体素voxel的中心点位置
给volumevisualization1可视化节点设置更丰富的颜色,Volume1结果为:
eg.可视化为表面
直接使用上面已创建的节点,把volumevisualization1可视化节点替换为Convert节点(设置为Group:选择density、FromType:Voluem)。滑动Convert节点的体积偏移VolumeOffset值,场景中的volume1显示为对应的密度,如下图所示为VolumeOffset值0.2到0.7的变化:
3、向量VectorVolume设置与可视化
可视化又可显示为:颜色可视化、方向可视化。
eg.颜色可视化
创建一个Volume2节点,设置为:Rank:Vector标量、Name:velocity(方便后面脚本引用)、InitialValue:1,0,0),UniformSamplingDivs:50(把Volume细分为50*50*50)。下图为标量SalarVolume与向量VetorVolume属性对比:
添加连接一个volumevisualization3可视化节点,对节点设置如下:
在上面两个节点中间添加一个VolumeWrangle节点(velocity),写入下面代码:
v@velocity = set(chf('x'), chf('y'), chf('z'));
x、y、z值对应可视化节点色条值
eg.方向可视化
用粒子代替体素voxel,用跟踪节点trail节点显示轨迹/方向,具体操作为:
直接使用上面已创建的节点,volumevisualization3替换为scatter节点,添加volumeTrail节点(scatter连第一个输入点,VolumeWrangle节点(velocity)连第二个输入点),结果(1,1,0.5)为:
4、几何体与体积Volume
创建一个Sphere节点、isooffset节点,并依次连接。
isooffset节点作用:把Sphere小球转为Volume,小球的体积Volume实际上还是一个矩形,只是把小球之外的密度置为0。
添加volumevisualization4节点,设置下颜色(密度0为绿色),结果为:
5、Volume属性——位置@P
位置属性@P:每个体素voxel的中心点位置。可以通过@P.x、@P.y、@P.z访问不同轴向位置值
6、Volume属性——voxel与索引
i@ix, i@iy, i@iz :体素voxel在各个方向上的索引(范围)。
i@resx, i@resy, i@resz:Volume在各个方向上的长度(各个方向有多少个体素voxel)。
eg.创建volume3节点(scalar、命名density、细分:50)、VolumeWrangle节点、volumevisualization5可视化节点,依次连接。写入以下代码:
//密度根据x轴方向的体素voxel索引值变化
f@density = i@ix / float(i@resx);
//因为细分已经设置为50,所以有50*50*50个体素voxel
//所以i@ix索引值为0~49、i@resx值为50
结果为,Volume密度沿X轴方向变化,可视化结果截图如下:+
7、Voluem函数——volumesample()
volumesample():返回指定点密度值。点击查看官方文档介绍。
eg.添加volume节点(scalar、命名desity、细分50)、VolumeWrangle节点(init),连接并输入以下代码:
f@density = noise(@P * 2); //赋予随机密度,随机函数返回随机值0.3~0.7
继续在下方添加连接VolumeWrangel节点(volumesample),
继续添加Add节点(添加一个点,随便移动下位置),连接在volumesample节点的第二个输入点,volumesample节点输入以下代码:
vector pos = point(1, 'P', 0); //pos=添加点的位置
float dist = distance(@P, pos); //体素与添加点的距离
float d = volumesample(0, 'density', pos); //对添加点进行取样,即获取添加点的密度值
if(dist < d*0.5){ //如果体素与添加点小于某个阈值,则执行if内代码
f@density = d;
}else{
f@density = 0;
}
最后添加一个volumevisualization6可视化节点,并随便设置下颜色,结果为:
(有兴趣可以尝试随机移动Add节点的点)。
8、Voluem函数——volumesamplev()
volumesamplev():返回指定位置块矢量值(方向密度值)。点击查看官方文档介绍。
eg.添加volume5节点(vector、命名velocity、细分50)、VolumeWrangle节点(init2),scatter2节点、volumetrail2跟踪节点,按下图连接并输入以下代码:
v@velocity = noise(@P * chf('scale')+@Time) - set(0.5, 0.5, 0.5);
//给volume设置个随机密度值
结果:第0帧时间、滑动通道scale 值(0,1,2,3,4,5)。这步与前面向量体积VectorVolume可视化类似
添加小球sphere2节点、PointWrangle(volumesampelv)节点、merge1节点,按下图连接并输入代码:
vector v = volumesamplev(1, 'velocity', @P);
@P += v * chf('scale2');
//对小球的位置重新取值(小球位置点对应的密度值/向量值)
第0帧,小球初始大小设置为0.5,init2节点 scale值设为3,滑动通道scale2,结果为:
感兴趣的朋友可以结合前面的init2节点的时间属性及scale值,查看小球变化。
9、Volume函数——volumepostoindex与volumeindextopos
volumepostoindex:pos to idnex,体素位置转为索引值
volumeindextopos:index to pos,体素索引值转为位置(坐标值)
eg.创建小球节点Sphere(缩放0.5、Frequency:20)、delete节点(Pattern:*、勾选KeepPoints)、Volume6节点(scalar、density、1、细分25)、PointWrangle节点(volumepostoindex),写入代码:
vector index = volumepostoindex(1, 'density', @P); //返回小球@P位置的体素索引值
v@index = index;
继续添加PointWrangle节点写入以下代码(volumeindextopos):
vector vpos = volumeindextopos(1, 'density', v@index); //返回索引值对应的体素位置
@P = vpos; //小球位置@P根据vpos值更新
继续添加Fuse节点(融合重复点)、box1节点、copytopoints1节点(缩放=1/voluem6的细分),按下图连接,结果为:点已被box替代
10、Volume调试
对Voluem添加点点和点属性,及添加颜色节点。可以更直观地查看密度变化和直接在表格中查看数值。
eg.添加Volume7节点(scalar、density、1、细分50)、gorup节点(命名volume、类型Primitives)、VolumeWrangle节点(init3),依次连接并写入以下代码:
f@density = noise(@P*2); //每个体素赋予随机密度 0.3~0.7
结果与【2、标量ScalarVoluem设置与可视化——eg.可视化为颜色】类似
继续添加并连接 VoluemWrangle节点(debug),写入以下代码:
float d = f@density; //体素的随机密度值
int pt = addpoint(0, @P); //在每个体素中心点位置@P添加点
setpointattrib(0, 'density', pt, d); //对添加的点设置点属性,属性值为体素的密度值
// 可以在表格中查看@density的值
继续添加split节点(Group:volume)(把volume和添加的点分成两组)、null节点(points)(连接第二个输出点,即点组)、color节点(colorTyoe:RampfromAttribute、Attribute:density、设置颜色),结果为: