欢迎光临散文网 会员登陆 & 注册

Houdini学习笔记021_VEX函数和循环语句

2022-09-01 13:09 作者:独孤嘌呤  | 我要投稿

今天讲解的内容分为两个部分:(一)自定义函数;(二)for循环语句。

案例是石墨烯的六边形蜂窝状平面,因为我本职工作是科学可视化,所以在案例选择上会更偏向于自然和科学。在笔记005中我已经用Copy节点制作过一遍,今天我们尝试用VEX来解决。

石墨烯(Graphene)

(一)自定义函数

什么是函数?

数学中的函数是指一个量随着另一个量的变化而变化,前者叫因变量,后者叫自变量。计算机中的函数与之类似,有一个输入端和一个输出端,从输入端输入初始值,输出端就会返回对应的结果。因此,函数可以看做是可实现特定功能的封装模块,比如sin(π/6) = 0.5,就是求正弦值的函数。而函数的英文单词function本身也有功能的含义。

Houdini的VEX中提供了大量的函数,在帮助文档中搜索VEX Functions就可以看到全部的函数用法。一般写法为函数名(变量1; 变量2...)

比如在这里,我们先要创建一个正六边形,用到的是创建点和面的函数。新建一个Point Wrangle节点(/obj/geo节点内创建,别把最开始学的基础忘了),在VEXpression栏输入“addpoint(”就会弹出如下提示(我试了下,一般是在输入左半边括号后弹出)。这是一个添加点的节点,我们用的是int addpoint(int geohandle, vector pos)的写法。geohandle是输入端口号,pos就是坐标。

三维空间中的坐标显然是一个矢量型数据,用VEX书写时可以用花括号括起来,如{0,0,0}。例如,在VEXpression中输入如下所示的语句,就可以在视图中显示新增的点。注意这里Run Over方式要选择Detail(only once),因为当前只有一个Point Wrangle节点,我们是将其作为一个独立的对象来看待的。

学会了单个点的创建,那么创建六边形的六个顶点自然不在话下。假设我们要创建的六边形边长为1,其六个点的坐标如下所示——

我们从点(1,0,0)开始逆时针依次创建点,注意当坐标表示中有其他函数(如sqrt)时,则不能用花括号的写法,而应该用set函数来设置矢量。

写完之后,视图窗口中就会看到六个点——

接下来是面的创建,使用的是addprim函数。在其介绍中我们可以看到pt0、pt1、pt2…的字样,数据类型为int(整数型)。其实这些就是点的序号,按照一定顺序排列就能围成一个面。

在Geometry Spreadsheet窗口查看,可以看到使用addpoint函数创建点的时候,点的编号自动就有了(0~5)。

所以这里我们可以定义一个数组points[],其类型为int。数组中就是0, 1, 2, 3, 4, 5六个编号。然后addprim函数就可以直接按照这个数组内的编号顺序来生成面,写法如下("poly"是生成的primitive类型,这里为多边形面)——

至此,一个六边形面就得到了。

如果要创建蜂窝状排列的石墨烯,一个六边形还远远不够,得批量生产。为了避免每次生产都要写这么一大串代码,我们可以把它封装起来。比如现在我只给定一个坐标点位置,就能够以其为中心生成一个六边形。假设这个给定点坐标为pos,那么在计算六边形点坐标时加上pos就可以了。

下面是封装函数的写法,函数的主体部分用花括号{ }括起来。前面的void hexagon(vector pos)就是定义函数,void是VEX中定义函数的方式,意思是空返回值。在帮助文档中查看已有的函数会发现前面都有个默认的void,只是省略了书写而已。hexagon是自定义的函数名称,括号内是函数的变量,记住要声明变量的数据类型(这里位置坐标pos是矢量,所以是vector类型)。

比如现在我要在{1,0,0}位置生成一个边长为1的六边形,只需要将pos设为{1,0,0},然后直接调用hexagon函数即可。

以上都是准备工作,下面我们进入第二部分。


(二)for循环语句

根据蜂窝的排列方式,我们可以将其拆解为两个方向上的六边形重复排列。如下图所示,横向上呈现上下交错的排列方式,纵向则是直接平移堆叠的方式。

假设0号六边形的中心点坐标为{0,0,0},只需要计算出其他六边形的中心点坐标,然后执行hexagon函数即可。我们先单独看纵向,每次向上移动的距离为sqrt(3),初始的vector pos = {0,0,0},每次都移动一定的距离可以用for循环语句来实现。写法为:

for(int i = 0; i < total_number; i++)

{

}

如果你学过C语言,对这些应该都很熟悉。i就是循环的次数编号,类型为整数,从0开始。i < total_number是循环发生的条件,这里的意思是达到total_number次循环就终止。最后的i++意思是每次循环后,i的值加1。{ }内部就是每次循环执行的内容,这里需要每次让pos坐标值沿z轴正向移动sqrt(3)的距离,即pos += set(0,0,sqrt(3));再执行hexagon(pos)函数。

但是执行后我们发现只有初始位置出现了六边形面,其他位置只出现了顶点。发生了什么呢?

其实在写代码的过程中出现这种现象是很正常的。因为我们不可能一开始就把所有的注意事项都考虑到,通常是在操作过程中不断去完善。如果你现在查看节点信息可以看到,其实是有5个Primitives生成的,只不过现在都是在原点位置处生成的。

原因是hexagon函数中,我们定义的points数组就是0~5的编号,所以每次创建六边形时用的都是0~5号点。而随着循环的不断进行,新生成的点的序号也是在不断增加的。所以需要把数组中的编号也要重新设置下。这里我采用的办法是直接让addpoint函数返回点的编号值,因为帮助文档中有这么一句:

Return就是返回的意思,返回的内容是所创建点的点序号,如果无法创建点则返回-1。于是我在每个addpoint函数前加了个int型变量来接受这个返回值,从pt0到pt6,如下图所示。同时,points[]数组的写法也要做出些变化,同样是参考的帮助文档。

现在执行循环就有没问题了~

纵向的解决了,我们再来看看横向的,情况要稍微复杂些,因为有上下交错的变化。这里可分为两种情况,当循环次数为奇数时,z方向坐标会移动sqrt(3)/2,;当循环次数为偶数时,z方向坐标又移动-sqrt(3)/2。此外,x方向每次移动的距离都是1.5。

我的写法是,在sqrt(3)/2前面乘上一个系数,pow(-1,i+1)意思是-1的i+1次幂。

将上面两个for循环结合起来,先沿着纵向每次生成第一个六边形,然后分别沿横向生成交错的六边形。具体代码如下,我就不作详细解释了。

运行结果如下——

最后,你可以把循环条件中的限定次数设为可调节的参数(方法参照上两篇VEX笔记),通过滑块就可以调节生成的石墨烯大小。

今天的学习就到这里吧,感谢各位的阅读,下回见~

Tips:书写代码时为了便于阅读,同一层级的代码最好使用相同的缩进值。VEXpression中按【Tab】键是缩进,【Shift+Tab】是缩退。养成良好的书写习惯,修正代码会更加高效。

Houdini学习笔记021_VEX函数和循环语句的评论 (共 条)

分享到微博请遵守国家法律