第026封“情书”:中国移动 VEX Space Filling Curves<Entagma>Houdini 2016 |
【注:首发于同名公众号”致houdini的情书“】
█我知道这一生注定要在这人世间兜兜转转一辈子,虽然上帝不会画直线,但这条道路是不是太曲折了?—每天翻译一篇教程,这就是我写给houdini的情书。【同名公众号:“致houdini的情书”】【今天是41岁第364天周四】第026封“情书”
▉世上应该没有直达终点的人生路,因为从上帝视角来看直达的道路少了些美感,人们会错过了误入歧途的机会,以及沿途的风景吧!
我想对于上班族比较糟糕的一部分除了不能自由支配时间,可能就是:每日的奔波苦,作为资深北漂早高峰上班狗,记录一下我的上班路:
(前方预警:全是废话可以略过)出家门,浑身摸一遍需要带的东西都在锁门,下楼走一段路,扫码骑5分钟共享单车,到地铁站外停车扫码锁车,有时候还会“归还异常”耽误个几分钟,转弯走几步随着人流上桥,现在始发站人越来越多了,有时多的从地铁口排出满满一桥的人,有一次桥产生的共振晃晃悠悠真的要塌的感觉,好不容易挪进地铁口,拿包的还要慢一些过机器安检,争先恐后的往传送带上扔包,有的被从无包通道拦下插过来的。过安检拿到各自包,快走几步刷卡,走几步转弯下楼梯,在站台固定的位置排队等车,车门打开冲进车厢,抢站在靠门的位置,为40分钟分钟后冲出车厢做准备,此门下车时正对着楼梯,门口的人不自觉的都会冲出车门快速上楼梯,迅速转几个人流疏导护栏的大弯,空荡的大厅的人突然像是冒出来的一样,在混乱交织人群里要见缝插针,转弯下楼梯,一定要走到那个指挥岛旁站排队,等车门打开,人群往里挤,要不动声色的默默的掐算最佳时刻,再挤进车厢占据门口最佳位置,当然不是每次运气那么好,经常感觉已经挤满了,就在门口,这时候默念:快关门。大概率后面又会挤进一波,就推到车厢里了。就一站路,从车厢里往外突围还是费些时间,再加上下车正处在楼梯位置,上下的人流在楼梯上仿佛都在慢放寸步难行,但过了这一段,稍微可以加快速度匆匆的左弯右转,再下长长的扶梯,一段长长的换乘通道,看着对面堵塞在上扶梯前的人密密麻麻,后面还有浩浩荡荡的上班族们,在络绎不绝的涌过来,环顾四周,年轻的人匆匆而过,心里稍微矫情一下:在这个2000多万人的大城市里,有多少人在前仆后继的追逐着自己的梦想。作为曾经年轻过的人,也曾在追逐梦想道路上狂奔,但绝想不到奋斗十多年后自己还是这般光景,打拼多年后中年竟还是个苦行僧般的上班狗,不觉有些羞耻感,人生真是变幻莫测啊。再转个弯,前面人为收窄路口,人流的流速又慢下来汇成了个暂时的堰塞湖,在下扶梯前,再经过一个n个方向的人流的大厅时,需要稍微施展一下凌波微步互相闪过,下扶梯,这时心情放松一些,虽然还要与出车厢上楼梯的再交织一会,毕竟再坐两站就逃离这换乘的美好时光了,等车排队,再进车厢,坐两站,这站下车人少,还是要挤一下才能挤出车厢的,转弯上扶梯,此时要马上掏出手机,打开软件,转个弯扫码出闸口一下就松口气了,再走200米转弯,上扶梯,出地铁。走到单位,打卡,下班再反方向重复一遍。如此这般,从13年走这条线到现在,我想未来不久可能不会再走这条路了。
向着42岁狂奔的你,应该明白了,在时间有限公司里,你的时间不多了,不能再重复以前的生活,把生命浪费在有意义的事情上,从今以后要开始新的篇章。
这一节我们要看一下:
6个随机出发的点左转右转完美的躲过各自路线却始终逃不出box的手掌心是如何实现的?
▉今天是41岁第364天周四
这是写给houdini的
第026封“情书”
geo流程图
volumevop流程图
1
box如何得到均匀分布的点
1)首先vdbfrompolygon。
2)volumevop用常量保证内部密度=1
3)pointfromvolume有两种均匀分布四边&六边
2
pgfind函数-寻找点函数
intclosepts[] =pgfind(0,"food",@P,maxrad, maxpt, maxrad); //food=在food组里找;第一个maxrad=寻找半径;maxpt=寻找最大数,第二个maxrad是搜寻精度,只要不是零都可以。 |
3
setpointgroup函数
setpointgroup(0,“food”,@ptnum,1); |
4
随机选择10个点作为出发点
1)for循环
for(inti=0; i<10; i++){ |
2)使用rand函数乘“所有点”
int ptid = int(rand(i)*@numpt); |
3)选出的点移入active组,再移出food组
setpointgroup(0,"active",ptid,1); setpointgroup(0,"food",ptid,0); |
5
寻找下个激活点的几种可能性
1)首先active组内:
a。有初始点; 如果active组为真就是存在点
if(@group_active == 1){ |
b。没有初始点:nearpoint函数找新的初始点
else{ |
2)其次active组外,找下一个激活点时:
a。附近有点,有点时使用连线代码;
if(nclosepts>0){ |
b。附近没有点:退出
6
初始点如何在6个激活点中随机选择一点
1)找几个激活点的列表 :closepts[]
a) 用pgfind函数
intclosepts[] =pgfind(0,"food",@P,maxrad, maxpt, maxrad); |
2)求激活点的数量 : nclosepts
a) 用len长度函数
int nclosepts = len(closepts); |
3)求与nclosepts激活点数量内的随机值:dir
a) 用(rand随机函数+int整数函数)*随机点数量;
b) 用滑块变量作为:随机因子seed
int dir = int(rand(@ptnum+chi("seed"))*nclosepts); |
3)最后获得随机选择的那个激活点:ptid
a) 用closepts[dir]列表表达式
if(nclosepts>0){ //当激活点数量>0时执行找随机的激活点的代码 int ptid = closepts[dir]; |
7
连线之后要注意使用setpointgroup函数
1)把激活点:ptid移入active组里作为初始点。移出food组。
2)而之前的初始点@ptnum(也就是当前点)全部从两个组中移出。不再参与计算
int newprim = addprim(0,"polyline"); addvertex(0,newprim,@ptnum); addvertex(0,newprim,ptid); setpointgroup(0,"active",ptid,1); setpointgroup(0,"active",@ptnum,0); setpointgroup(0,"food",ptid,0); setpointgroup(0,"food",@ptnum,0); |
8
最后一种情况,初始点周围没有激活点时
1)重新寻找新的初始点:nptid
a) 用nearpoint函数
int nptid =nearpoint(0,"food",@P); |
2)同样注意nptid移入active,移出food;而@ptnum移除所有组;
setpointgroup(0,"active",nptid,1); setpointgroup(0,"food",nptid,0); setpointgroup(0,"food",@ptnum,0); setpointgroup(0,"active",@ptnum,0); |
以下
理论部分
(一)空间的点横平竖直连接的运行原理
要实现在3d空间中的管道:首先让我们先从一个均匀间隔的点在3d空间网格说起;网格中所有点都是相同距离。
原理)
1 active激活点寻找六个最接近的点;
2 一旦找到,随机选择一个点作为下一个激活点;
3 它与之前的激活点之间连接line;
4 把上一个点设为 inactive;new 点将不再找old点
(二)pcfind和pgfind的差别
pcfind函数:
pgfind函数:
两者非常相似。
不同之处在于:它们使用基于网格的加速结构。pgfind多了个divsize。这是网格参数,在一定的网格大小里进行寻找。官方说:正确的divsize(网格大小),可以提供更快的初始化和查找。我测试只要不是非常小,随便一个数值都可以,非常小比如=0,它在更小的空间里寻找一遍,所以会花很长计算时间。
divsize的值不同,它们形态都一样。速度也一样。0的时候会算很久
开始正式制作
使用软件houdini16.5
1)box1
a) Size=2*2;100*100
第1步:均匀分散点
2)vdbfrompolygons1:
a) Voxel size=0.01
b) Fog VDB:density
红色密度=1,边缘的密度<1
第2步:保证密度是均匀的
3)volumevop1 蜂巢化
3-4)constant1
a) Float default=1
box内部密度=1
第3步对于均匀分散点关键:
4)pointfromvolume1
点配置方式两种:grid四边形;Tetrahedral六边形
grid方式
Tetrahedral六边形方式
首先划分“激活”与“非激活”点组
问题1: 如何用vex把所有点移入一个组 方案)使用setpointgroup函数,现在所有点都在food组里:
5)pointwrangle1
a)所有点都划归food组里
setpointgroup(0,“food”,@ptnum,1); //设置所有点到active组 1=添加到group,0=移出group |
所有点都是在group:food里
方案)
a) 用for循环10次。
b) 再用rand函数从food组的所有点里随机的一个点,把它划归active组,同时再移出food组。这就是所有的起始点了。这样运行10次,就选出了10个点。
6)Pointwrangle2:
a)Run Over:Detail(Only once)
for(inti=0; i<10; i++){ //运行10次循环也就是有十个起始点 //int ptid = int(rand(i)); 创建另一个变量,是一个随机的整数,应该从0到最大的点数, int ptid = int(rand(i)*@numpt); //rand从0~1,乘总数就得到所有的点的id随机值,这样它会随机选择 setpointgroup(0,"active",ptid,1); //设置“出发点”在active组 setpointgroup(0,"food",ptid,0); //把“出发点”移出food组 } |
我们要使用active组的点并非永远都会找到,如果有的区域已经没有了可以激活的点,这种情况:
问题3:寻找附近下一个激活点时会有哪几种可能性!
可能性:
1)首先active组内:
a。有初始点;执行下面代码
b。没有初始点:退出。
if(@group_active == 1){ //当附近有激活点的时候 } else{ } |
2)其次active组外,找下一个激活点时:
a。附近有激活点,有点时连线代码;
b。附近没有激活点。当前这个初始点同时移出所有组; nearpoint函数不设置搜索半径遍历所有的可能的点,再选择一个新的点作为初始点。
问题4-1:初始点如何在周围的可用的激活点中,如何随机选择一点
方案)找到六个点;再判断如何随机选择其中一个作为下一个激活点:
a) 在初始点周围的food组里,一定半径范围内,用pgfind函数找6个邻近点。
b) 使用rand函数结合6个临近点id得到一个随机变量,随机选择“6个点的列表”中的值,得到下一个激活点ptid的id。
问题4-2:初始点与激活点如何连线
方案)创建polyline和vertex;
a) addprim函数创建polyline
b) addvertex函数创建新的激活点ptid的顶点,当前点@ptnum的顶点。
3) 对新的激活点移入active组,移出food组,当前点同时移出active和food两个组。
a) 用setpointgroup()函数做点的移入或移出组的操作。
int maxpt = 6; //首先定义变量 float maxrad = 0.06; //设置最大半径比pointfromvolume的point sepration大些 //因为它会运算所有点,它们只需要在指定的组运行。所以用条件判断一下 if(@group_active == 1){ //如果active组里有点 intclosepts[] =pgfind(0,"food",@P,maxrad, maxpt, maxrad); //food在food组里找;第一个maxrad=寻找半径;maxpt=寻找最大数,第二个maxrad是搜寻精度,只要不是零都可以。 //用len函数求得点的数量,创建另一个变量! int nclosepts = len(closepts); //从这6个点中随机选择一个点。创建一个方向变量 intdir = int(rand(@ptnum+chi("seed"))*nclosepts); //随机在ptnum中,再加一个滑块参数,0~1变成整数会是0或1, //在得到整数之前,乘点的数量(长度),得到一个介于0和最大值(6)之间的随机数。 //特殊情况:如果不检查继续下去,可能暂时有效果,因为有的“激活点”周围有可能没有“非激活点”所以if判断一下这种情况, if(nclosepts>0){ //如果有临近点,随机选择一个 intptid = closepts[dir]; //创建另一个变量,随机选择一个点 int newprim = addprim(0,"polyline");//我们在两点之间建立线 addvertex(0,newprim,@ptnum); addvertex(0,newprim,ptid); setpointgroup(0,"active",ptid,1); setpointgroup(0,"active",@ptnum,0); setpointgroup(0,"food",ptid,0); setpointgroup(0,"food",@ptnum,0); } |
方案)不要使用创建polyline函数,只需要用nearpoint函数,在food全组中寻找“最近的一个可用点” ,然后再把这个新的激活点移入active组,移出food组,进入下一次循环:而之前的那个周围没有可用点的“当前点”作为old点移出所有组,
else{ //如果没有附近点,我们再找一个可用的点,用nearpoint函数,不限制半径它会搜索整个food group int nptid =nearpoint(0,"food",@P); //找到这个点不要连线,它会产生跳跃线条。 setpointgroup(0,"active",nptid,1); setpointgroup(0,"food",nptid,0); setpointgroup(0,"food",@ptnum,0); setpointgroup(0,"active",@ptnum,0);//当前点移出所有组 } } |
代码部分全部结束,使用solver让代码循环操作。
7)solver1
1) 把pointwrangle3拷入。
去掉显示food组的点。
8)delete1
9)polyline 最后管道视觉化
今天就到这儿了,收功
教程翻译自entagma的网络教程
下一节:20161212 Special Guest- Noseman - Creating Digital Assets For Cinema 4D