第026封“情书”:中国移动 VEX Space Filling Curves

第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*2100*100


1步:均匀分散点

2)vdbfrompolygons1:


    a)  Voxel size=0.01 

    b)  Fog VDBdensity

红色密度=1,边缘的密度<1


2步:保证密度是均匀的


3)volumevop1  蜂巢化 


3-4)constant1


    a)   Float default=1

box内部密度=1


3对于均匀分散点关键:


4)pointfromvolume1


点配置方式两种:grid四边形;Tetrahedral六边形


grid方式

Tetrahedral六边形方式


1

首先划分“激活”与“非激活”点组

问题1: 如何用vex把所有点移入一个组

 方案)使用setpointgroup函数,现在所有点都在food组里:

5)pointwrangle1 

    a)所有点都划归food组里

setpointgroup(0,“food”,@ptnum,1); //设置所有点到active组   1=添加到group,0=移出group 

所有点都是在group:food里

问题2: 如何用vex设置“起始点”

方案)

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); //rand0~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;  //设置最大半径比pointfromvolumepoint sepration大些

//因为它会运算所有点,它们只需要在指定的组运行。所以用条件判断一下

if(@group_active == 1){  //如果active组里有点

    intclosepts[] =pgfind(0,"food",@P,maxrad, maxpt, maxrad); //foodfood组里找;第一个maxrad=寻找半径;maxpt=寻找最大数,第二个maxrad是搜寻精度,只要不是零都可以。

//用len函数求得点的数量,创建另一个变量!

    int nclosepts = len(closepts);

    //从这6个点中随机选择一个点。创建一个方向变量

    intdir = int(rand(@ptnum+chi("seed"))*nclosepts);  //随机在ptnum中,再加一个滑块参数,0~1变成整数会是01

    //在得到整数之前,乘点的数量(长度),得到一个介于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);

    }


问题4-3: active组有 点时,而周围还能可用的激活点时, 点与点如何连接

方案)不要使用创建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

你可能感兴趣的:(houdini)