伏雨朝寒悉不胜,那能还傍杏花行。去年高摘斗轻盈。漫惹炉烟双袖紫,空将酒晕一衫青。人间何处问多情。 ———— 纳兰容若
Houdini
一直听说湖边小屋是程序化建模的朝圣,虽然所有的大佬都在说新手远离!但是就不信这个邪,就兴冲冲去尝试学习了一下(事实证明,这个提醒是非常明智的,但是死磕VEX倒是很快取得了一些小小的熟练度),而教程本身带来的主要的障碍在于Houdini版本不同导致某些函数和节点需要重新整理,而且作者自身计算的时候也存在一些问题,还有谷歌实时翻译不停出错误!幸好在知乎上看到了大佬的记录分析,在17个小时的原教程基础上结合大佬的一些阐释和我自己的一些检验,重新复现了湖边小屋的全过程,大概得到以下缩略版的思路总结。详细的步骤可以跳转冬青大佬的知乎页面。
一、盒体基础
(1)box随机分配
在box中加入box_id作为筛选基础(后续的所有面片的指代其实也都通过id来实现)构建点云得到内部四个以2为单位长度的点,随机选取并作为下一个盒体的center
(2)构建vdb
本步的主要作用是通过vdb resample盒体,实现类似布尔运算的效果,然后将密集的高面盒体对其顶点进行四舍五入网格化操作,然后把点融合掉,实现盒体的模数化。 小技巧:vdb可能产生一定的位置偏移,可以用移动$YMIN这样的方法校正
(3)求小阳台
本步骤主要目标是找到在二层凸起的面,并把盒体回缩一些作为小阳台。此步骤总体上分为三部分。
- 第一部分,求投影。
效果是把二层拉平到底层然后fuse,但是这里会有重合面(作者也指出了),所以用射线检测的方法,在下面的面中心上采用一个射线向上发射的方法,求到相交的面后删除。然后拉平,就会实现悬空的面法线向上,地面的面法线向下的情况
- 第二部分,求突出面(footprint)
作者采用了一种点检测的方法(图源作者的介绍)后续作者在很多地方都使用了这个方法或者它的变体,本文就不再详细赘述。首先wrangle中遍历每一个面,把这个面的四个顶点都记录下来到一个数组,然后通过pointprims函数获取这些顶点所从属的面并存放在另外一个neighs数组当中,贴一下代码。
int pts[] = primpoints(0, @primnum); //获取一个面的四个顶点的序列号
int neighbours_pcheck[], neighbours_pcheck_all[];
foreach(int pt; pts)
{
//把该面的四个顶点相邻的面找出来
neighbours_pcheck = pointprims(0, pt);//获取一个点所在的面的序列号
append(neighbours_pcheck_all, neighbours_pcheck);
}
int max_nm = max(neighbours_pcheck_all);
int found;
int neighbors_prim[];
for(int i=0; i<=max_nm; i++)
{
//如果有两个公共点,则这两个面相邻
if(i != @primnum)
{
found = 0;
foreach(int j;neighbours_pcheck_all)
{
if(i == j)
{
found++;
}
}
//如果该面被找到两次,说明有两个公共点
if(found > 0 && found%2 == 0)
{
append(neighbors_prim, i);
}
}
}
这个时候如果neighs里面的面上出现了两次的(遍历自身的for),就说明它是原来面的相邻面,保存到新neighs_real数组中,在突出面的应用中就是只有一个相邻面的情况下就被标记为突出面。同时,该面的四个顶点的法线也被变换到了指向相邻面的方向
- 第三部分,回缩阳台
利用group节点生成bounding box来形成group选出原有体积的四个外侧点(根据变换后的法线sort排序后blast出01得出)实现变换。上图
(4)分配面属性
没啥好说的,重新计算一次法线,然后根据法线方向和面积为各个面片赋值给wall,roof,support, floor
至此,第一部分盒体结束,开始第二部分房顶。
本文参考:知乎冬青大佬的解析文章 湖边小屋解析专栏 b站转载的原教程视频湖边小屋教程(建议可以用chrome的英文字幕插件来进行观看)