第084封“情书”:石更20190218 Polyfolding- Part 1卷曲<Entagma>Houdini 2019
▉ 岁月没有把我的灵魂磨平,只是擦掉了上面的冲动和轻狂,它依然棱角分明。— 每天翻译一篇教程,这就是我写给houdini的情书。【首发于同名公众号:“致houdini的情书”】
【】█ 永不妥协:当现实抬手给你一巴掌的时候,你应该和它击个掌。就算是破罐子,也要摔的比别人响!”
前言不搭后语
西西弗斯是古希腊神话中的一个悲剧人物,因为泄露了宙斯的秘密后又背叛了死神的承诺而被众神惩罚。
每天周而复始地进行无意义的工作——将一块巨石从山脚推到山顶,可是巨石太重一到达山顶又会因为自重滚落回山脚。西西弗斯的生命就在这样一件无效又无望的劳作当中慢慢消耗殆尽。
但他没有跪地求饶。
本节内容为物体表面每个primitive创建变换矩阵今天是42岁第057天周五
84这是写给Houdini的第084封“情书”
我是geo流程图
❖ 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都被视为单个对象,并附有自己独特的转换矩阵。然后,可以将它们置于层次关系中以使连续卷曲发生。
A01
创建几何体
B02
用参数表示几何到add点的距离
C03
可视化dist属性
D04
按照dist属性排列prim
E05
按设定的逻辑寻找每个prim的父物体
F06
收集所有的父物体
G07
找到边界点
H08
纠正边界特殊情况(parent<0)
I09
构建矩阵系统
J10
可视化系统
K11
修正矢量方向
接下来正式制作 使用软件:houdini17.5
○ 节点 ○
○ 具体操作 ○geo重命名polyfolding:。01)sphere:a)polygon;b)Frequency=2002)mountain:变形几何体。03)add1:增加一个点
❖ 小目标 ❖
a)把几何体分解成单独的prim。b)单独对待prim
❖ 分析 ❖ 🔗 需要在geo层级进行变换,但没有针对单独prim的转换,所以这里需要做转换。 🔗 还需要一个metric(度规)来分割。 🔗 我们不要仅有的单独prim,而是形成结构化的,把单独的prim放进“父子关系”的结构中。 🔗 然后确定哪些polygon一起移动或者一起卷曲。
○ 节点 ○
❖ 小目标 ❖ 首先创建物体表面到“add点”的距离dist
❖ 执行 ❖ 04)primitivewrangle:命名“parametrize” a)add连接到“接口2”
//-- 引入add点的位置 vector tar_pos = point(1,"P",0); //-- 距离变量 float dist = length(@P - tar_pos); //-- 变量写到属性上 @dist = dist;
○ 节点 ○
❖ 具体操作 ❖
05)visualize1: ❖ 小问题 ❖primid排列从上到下,没有按照到add点的距离排列。
○ 节点 ○
❖ 小目标 ❖需要primid按照dist距离来分布🔗 解决方案 🔗
06)sort: 按照dist距离的大小,primID从小到大分布,
○ 节点 ○
❖ 小目标 ❖
用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的就是没有父物体的三角形
○ 节点 ○
❖ 阶段目标 ❖
用递归遍历所有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和“父”的边界
(最终沿这条边旋转,所以必须把新坐标系的原点放在这条边的中间位置)
○ 节点 ○
对于找到的边界点,要在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数组
❖小问题❖
“边界点”数组有些是空的。
🔗 解决方案 🔗
必须为这些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轴,对原点坐标系的变换)
○ 节点 ○
○ 具体操作 ○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,这样所有运算都能工作。
○ 具体操作 ○01)创建可视化。
接下来段动
○ 小问题○
a)红色矢量总是跟“父prim”的“交界边”平行。b)点序号的任意排序,使tangent矢量指向混乱。而“父子关系”是一个连续的tangent指向。
🔗❖ 小目标 ❖🔗
需要一致性的tangent矢量指向(蓝色)
🔗 解决方案 🔗
将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
公众号: 微信号
- 第085封“情书”:石达开Polyfolding - Part 2<Entagma>Houdini 2019
- 第090封“情书”: 一生二Vellum Cell Replication Tutorial - Part 2<Entagma>Houdini 2019
- 第087封“情书”:红旗下的蛋Analytical Foam分析泡沫<Entagma>Houdini 2019
- 第093封“情书”:三生万物Vellum Cell ReplicationPart3 <Entagma>Houdini 2019
- 第097封“情书”:浮生碌碌PDG For Design Work Pt. 4 - Distributed Grains Using PDG<Entagma>Houdini 2019
- 第098封“情书”:我有病Distributed Rendering Using Redshift<Entagma>Houdini 2019
- 第092封“情书”:三国Vellum Cell Replication 2c<Entagma>Houdini 2019
- 第094封“情书”:变量20190312PDGForDesignWorkPt1-TheBasics<Entagma>Houdini 2019
- 第084封“情书”:方阵 PDG For Design Work Pt. 1b - Generating Mosaics Out Of Your Renders<Entagma>Houdini 201
- 第089封“情书”:九九归一Vellum Cell Replication TutorialPART1<Adrian Meyer>Houdini 2019
- 第088封“情书”:万宗归一Procedural Subdivision Lines - Creating Control Curves<Entagma>Houdini 20
- 第099封“情书”:天下无不散之筵席Volumes101-DissolvingGeometry<Entagma>Houdini
- 点友商业需求文档BRD:2019社交新起点
- Protel99 画层次原理图、多Part元件的绘制方法的一些心得记录
- 创建自定义 AngularJS 指令:Part 7 Creating a Unique Value Directive using $asyncValidators
- PTA_2019春_059_ Huffman Codes
- 如何在org.eclipse.ui.part.ViewPart失去焦点时完成某些操作
- 论文阅读《Real-time part-based visual tracking via adaptive correlation filters》(1)
- Building Microservices with Spring Boot and Apache Thrift. Part 1 with servlet
- 2019最新火星人php实地培训基础课程 火星人php基础教程(63课)