您的位置:首页 > 其它

第084封“情书”:石更20190218 Polyfolding- Part 1卷曲<Entagma>Houdini 2019

2019-08-09 23:56 99 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/sinat_33115291/article/details/99008367

▉ 岁月没有把我的灵魂磨平,只是擦掉了上面的冲动和轻狂,它依然棱角分明。— 每天翻译一篇教程,这就是我写给houdini的情书。【首发于同名公众号:“致houdini的情书”】

 【】

█ 永不妥协当现实抬手给你一巴掌的时候,你应该和它击个掌。就算是破罐子,也要摔的比别人响!”

前言不搭后语

西西弗斯是古希腊神话中的一个悲剧人物,因为泄露了宙斯的秘密后又背叛了死神的承诺而被众神惩罚。

每天周而复始地进行无意义的工作——将一块巨石从山脚推到山顶,可是巨石太重一到达山顶又会因为自重滚落回山脚。西西弗斯的生命就在这样一件无效又无望的劳作当中慢慢消耗殆尽。

但他没有跪地求饶

本节内容为物体表面每个primitive创建变换矩阵

今天是42岁第057周五
84这是写给Houdini的第084封“情书”


我是geo流程图


我是vex代码

❖ add点到物体的距离 ❖  //-- 引入add点的位置    vector tar_pos = point(1,"P",0);    //-- 距离变量    float dist = length(@P - tar_pos);    //-- 变量写到属性上    @dist = dist;

❖ 每个prim的一个父prim  ❖//-- 1 首先,找到prim的临近三角形,    //每个三角形有三个邻居,其中一个作为父primint poly_neighbours[] = polyneighbours(0,@primnum);    //我们需要ID号最高的那个prim//-- 2 创建“父prim”的变量,    //用-1初始化,这不是可用的索引,如何在循环中做到这一点,int parent = -1;//-- 3 遍历所有的邻居,此循环结束,返回最大ID的nbrforeach(int nbr; poly_neighbours){    //- 3a “当前邻居id” 比较 “父prim变量” 来更新“父变量”    //- 3b 另外要补充,“只比当前id大的primid"    if(nbr > parent && nbr >@primnum){        parent = nbr;          }}i@parent = parent;


❖  收集每个prim的所有父prim ❖int parent = 0;int idx = @primnum;int parents[]; 


//-- 1 只要parent不是-1循环继续,=-1循环停止while(parent>=0){    //-- 2 首先引入parent    parent = prim(0,"parent",idx);    //-- 3 添加入数组    append(parents,parent);    idx = parent;    }//-- 4 颠倒数组顺序,-1在起始位置parents= reverse(parents);removeindex(parents,0);


i[]@parents = parents;
❖ prim与父的共享边的两个点  ❖//-- 1首先,需要"所有点"和“它们的parent点”int mypoints[] = primpoints(0,@primnum);int parpoints[] = primpoints(0,i@parent);


int edgepoints[];


//-- 2两个循环,遍历所有点中的所有的父的pointforeach(int pnt; mypoints){    foreach(int parpnt; parpoints){    //-- 3如果pnt与parpnt相同,点加入“edgepoints数组”        if(pnt == parpnt){            append(edgepoints, pnt);        }            }}//-- 4 补充排除parent<0的情况,取此prim的前两个点if(i@parent<0){    append(edgepoints, mypoints[0]);    append(edgepoints, mypoints[1]);}


i[]@edgepoints = edgepoints;

❖  创建矩阵 ❖//-- 1 两个边界点位置vector edgepos1 = point(0,"P",i[]@edgepoints[0]);vector edgepos2 = point(0,"P",i[]@edgepoints[1]);//-- 2 创建向量vector edge = edgepos2 - edgepos1;


//-- 3 创建矩阵基础:4个向量(x,y,z轴,对原点坐标系的变换)    //-- 3a 双切线:新矩阵的第一个方向vector bitangent = normalize(edge);    //-- 3b 法线vector normal = @N;    //-- 3c 切线:标准化积乘vector tangent = normalize(cross(bitangent,normal));    //-- 3d 第4个矢量= edge中心点到原点vector origin = edgepos1 + ( edge*0.5);


//-- 4 创建矩阵matrix xform = set(bitangent,normal,tangent,origin);


//-- 6 用向量的分量语法 x=第一个向量,a=第4个分量xform.xa = 0;xform.ya = 0;xform.za = 0;


//-- 5 创建矩阵属性4@xform = xform;❖    ❖

首先
制作步骤

 

小节提要

       Polyfolding折叠(多边形交叠包起)是一种有趣的效果,您可以将对象分割为各个条带并使它们卷曲。

     它可用于分解对象或使其从无到有。为了实现卷曲行为,需要一些矩阵数学。所有prim都被视为单个对象,并附有自己独特的转换矩阵。然后,可以将它们置于层次关系中以使连续卷曲发生。

A

01

创建几何体

B

02

用参数表示几何到add点的距离

C

03

可视化dist属性

D

04

按照dist属性排列prim      

E

05

按设定的逻辑寻找每个prim的父物体

F

06

收集所有的父物体

G

07

找到边界点

H

08

纠正边界特殊情况(parent<0)

I

09

构建矩阵系统

J

10

可视化系统

K

11

修正矢量方向

接下来
正式制作           使用软件:houdini17.5


01创建几何体


○ 节点 ○



○ 具体操作 ○geo重命名polyfolding:。01)sphere:a)polygon;b)Frequency=2002)mountain:变形几何体。03)add1:增加一个点 ❖ 小目标 ❖

a)把几何体分解成单独的prim。b)单独对待prim


❖ 分析 ❖ 🔗 需要在geo层级进行变换,但没有针对单独prim的转换,所以这里需要做转换。 🔗 还需要一个metric(度规)来分割。  🔗 我们不要仅有的单独prim,而是形成结构化的,把单独的prim放进“父子关系”的结构中。 🔗 然后确定哪些polygon一起移动或者一起卷曲。


02 用参数确定点到物体距离 


○ 节点 ○


❖ 小目标 ❖ 首先创建物体表面到“add点”的距离dist

❖ 执行 ❖    04)primitivewrangle:命名“parametrize”    a)add连接到“接口2”

    //-- 引入add点的位置    vector tar_pos = point(1,"P",0);    //-- 距离变量    float dist = length(@P - tar_pos);    //-- 变量写到属性上    @dist = dist;



03 可视化dist属性


○ 节点 ○

❖ 具体操作 ❖

    05)visualize1: ❖  小问题  ❖primid排列从上到下,没有按照到add点的距离排列。



04 按dist排序primid


○ 节点 ○


❖ 小目标 ❖需要primid按照dist距离来分布🔗 解决方案 🔗

   06)sort: 按照dist距离的大小,primID从小到大分布,


05 找到相邻父物体


○ 节点 ○


❖ 小目标 ❖

用primid来决定prim的父子属性,每个prim要按照我们设计的逻辑确定父子关系。


❖ 举个栗子 ❖
这里“ID:51”作为父prim,沿着中间边旋转

🔗 解决方案 🔗


找到每个prim的“父prim”


//-- 1 首先找到prim的临近三角形,int poly_neighbours[] = polyneighbours(0,@primnum);    //我们需要ID号最高的那个prim//-- 2 创建“父prim”的变量,    //用-1初始化,这不是可用的索引,如何在循环中做到这一点,int parent = -1;//-- 3 遍历所有的邻居,此循环结束,返回最大ID的nbrforeach(int nbr; poly_neighbours){    //- 3a “当前邻居id” 比较 “父prim变量” 来更新“父变量”    //- 3b 另外要补充,“只比当前id大的primid"    if(nbr > parent && nbr >@primnum){        parent = nbr;          }}i@parent = parent; 

❖ 举个栗子 ❖ primID:0的三个邻居中,找到ID最大的primID:6作为父prim

       

当前parent=-1的就是没有父物体的三角形



06 收集所有的父物体



○ 节点 ○


❖ 阶段目标 ❖

用递归遍历所有prim,并找到正确的顺序便大功告成

○ 小问题 ○

这里不支持递归

🔗 退而求其次-解决方案 🔗

收集每个prim的所有parent

父的父的父的父的父的...如此循环    08 primitivewrangle命名“gather_parent”


int parent = 0;int idx = @primnum;int parents[]; 


//-- 1 只要parent不是-1循环继续,=-1循环停止while(parent>=0){    //-- 2 首先引入parent    parent = prim(0,"parent",idx);    //-- 3 添加入数组    append(parents,parent);    idx = parent;    }i[]@parents = parents;


○ 小目标○

去掉parent数组中包含一个-1

🔗 解决方案 🔗


//-- 4 颠倒数组顺序,-1在起始位置parents= reverse(parents);removeindex(parents,0);


 ❖ 阶段目标 ❖

🔗   创建一个“矩阵系统”🔗    🔗有了所有的“父子结构”,接下来创建“矩阵”     🔗每个prim放入自己的空间坐标(为所有prim建立一个4*4的矩阵系统,为这个prim指定了“全局转换”当被视为一个物体时)🔗 第一步 🔗

🔗


接下来段动

🔗   创建“矩阵系统”准备工作🔗

1)有了所有的“父子结构”,接下来创建“矩阵” 

2)每个prim放入自己的空间坐标(为所有prim建立一个4*4的矩阵系统,为这个prim指定了“全局转换”当被视为一个物体时) 

🔗 第一步 🔗

○ 找到prim和“父”的边界

(最终沿这条边旋转,所以必须把新坐标系的原点放在这条边的中间位置)


07 与父prim的边界点


○ 节点 ○


对于找到的边界点,要在dian之间建立向量,进而构建矩阵。🔗 解决方案 🔗

1)这条边界的两个点,被两个prim共有

2)判断条件就是:pointid相同

🔗 执行 🔗09)primitivewrangle命名“find_edgepoints”。

//-- 1首先,需要"所有点"和“它们的parent点”int mypoints[] = primpoints(0,@primnum);int parpoints[] = primpoints(0,i@parent);


int edgepoints[];


//-- 2两个循环,遍历所有点中的所有的父的pointforeach(int pnt; mypoints){    foreach(int parpnt; parpoints){    //-- 3如果pnt与parpnt相同,点加入“edgepoints数组”        if(pnt == parpnt){            append(edgepoints, pnt);        }            }}i[]@edgepoints = edgepoints;


🔗 验证 🔗

id:0与它的父id:6的边的2个点放入了edgepoints数组


08 纠正边界情况

❖小问题❖

“边界点”数组有些是空的。

🔗 解决方案 🔗

必须为这些parent=-1增加边界点。

🔗 执行 🔗


//-- 4 补充排除parent<0的情况,取此prim的前两个点if(i@parent<0){    append(edgepoints, mypoints[0]);    append(edgepoints, mypoints[1]);}

🔗 完美 🔗


接下来段动

🔗   正式创建“矩阵系统”🔗1)收集所有必要的信息。2)矩阵的四个向量,每个向量4个浮点向量,虽然是三个向量,最后一个确定矢量是“旋转矢量”还是“位移矢量”。

🔗 第二步 🔗

矩阵基础:4个向量

(x,y,z轴,对原点坐标系的变换)


09 构建矩阵正交系统


○ 节点 ○



○ 具体操作 ○10)primitivewrangle命名“build_system”。

//-- 1 两个边界点位置vector edgepos1 = point(0,"P",i[]@edgepoints[0]);vector edgepos2 = point(0,"P",i[]@edgepoints[1]);//-- 2 创建向量vector edge = edgepos2 - edgepos1;


//-- 3 创建矩阵基础:4个向量(x,y,z轴,对原点坐标系的变换)    //-- 3a 双切线:新矩阵的第一个方向vector bitangent = normalize(edge);    //-- 3b 法线vector normal = @N;    //-- 3c 切线:标准化积乘vector tangent = normalize(cross(bitangent,normal));    //-- 3d 第4个矢量= edge中心点到原点vector origin = edgepos1 + ( edge*0.5);//-- 4 创建矩阵matrix xform = set(bitangent,normal,tangent,origin);//-- 5 创建矩阵属性4@xform = xform;

○ 小问题 ○

这里“xyz向量的第四个分量”应该=0

因为这三个是“矩阵的旋转部分”,否则不会起作用

🔗 解决方案 🔗

//-- 6 用向量的分量语法 x=第一个向量,a=第4个分量xform.xa = 0;xform.ya = 0;xform.za = 0;

把旋转矢量的第4个分量设为0,这样所有运算都能工作


10 可视化系统



○ 具体操作 ○01)创建可视化。   


接下来段动

○ 小问题○

a)红色矢量总是跟“父prim”的“交界边”平行。b)点序号的任意排序,使tangent矢量指向混乱。而“父子关系”是一个连续的tangent指向。


🔗❖ 小目标 ❖🔗

需要一致性的tangent矢量指向(蓝色



11 纠正矢量方向

🔗 解决方案 🔗

将bitangent矢量连接到“父子prim的中心”

🔗 执行 🔗

❖在创建“矩阵”之前纠正向量方向 

//-- 7 纠正向量方向

    //-- 7a 父prim位置

vector parpos = prim(0,"P",i@parent);

    //-- 7b 在父位置~当前位置形成向量

vector pardir = @P - parpos;

    //-- 7c 这个向量与“bitangent”点积 

    //然后判断:如果这个向量与tangent相同,点积为正。否则反。

if(dot(tangent,pardir)<0){   //-- 切线方向错了

   tangent *= -1.0; 

   }

❖ 效果 ❖

   
a)圆圈处tangent改变了方向。b)黄色就是一个连续的父子关系。

至此:每个单独prim创建了一个全局坐标系 ,现在每个prim有自己的变换矩阵,是整个例子最重要的部分。



教程翻译自entagma的网络教程下一节:20190304 Polyfolding - Part 2 

公众号: 微信号

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐