原视频:https://www.youtube.com/playlist?list=PLzRzqTjuGIDhiXsP0hN3qBxAZ6lkVfGDI
Bili:Houdini最强VEX算法教程 - VEX for Algorithmic Design_哔哩哔哩_bilibili
Houdini版本:19.5
递归是一种直接或者间接地调用自身的算法,一般计算机中的递归算法实现不适用于Houdini的Vex(通过函数或子过程来完成)。详情可见后面谢尔宾斯基三角的例子。
图片来自@bky2016的文章,感兴趣可以去看看。
本章主要使用以下几种方式实现递归:
A)、For-Each节点,
B)、For-Each节点 + VEX,
C)、Solver解算器,
D)、纯VEX(复杂),
提前剧透:B、C两种方法计算最快,
关于For-each节点,可以看这知乎@ZeTii的Houdini 中for-each 和for-loop 节点文章。
用上面的四种方法分别实现一根螺旋线,
①节点连接及设置如下,(代码节点的通道值自行设置),
②补充,节点代码如下,
// B——sprial_recursively节点代码
float steplenx = chf('steplenx');
float stepleny = chf('stepleny');
float stepang = chf('stepang');
vector pos = @P;
pos = pos + v@dir * steplenx; // pos沿X位移
matrix mat = ident();
rotate(mat, radians(stepang), set(0,1,0));
pos *= mat;
pos += set(0,1,0) * stepleny; // pos沿Y位移,即高度
int newpoint = addpoint(0, pos);
setpointattrib(0, 'dir', newpoint, v@dir);
//盲猜在For-Each循环内,除了第一次,其它循环不能访问外部属性
setpointgroup(0, 'last', newpoint, 1);
setpointgroup(0, 'last', @ptnum, 0);
// C——解算器Solver内代码
//与上面一样
// D——sprial_recursively1节点代码
vector pos = @P;
for(int i=0; i
本节主要用下面的方法实现谢尔宾斯基三角,(当然,也有其它方法),
For-Each实现方法,
其它三种实现原理大概如下,
②补充,节点代码如下,
// B——sierpinski_triangle节点代码
int pts[] = primpoints(0, @primnum);
for(int i=0; i
// C——解算器Solver内代码
//与上面一样
// D——sierpinski_triangle1节点内代码
int pts[] = primpoints(0, @primnum);
vector positions[] = array();
for(int i=0; i
eg.①节点设置及连接如下,
②补充,pointwrangle1节点代码如下,
float branchang = radians(chf('branchang')); //范围设 0~120
for(int i=0; i<3; i++){
float a = -branchang + i * branchang + f@ang; //妙鸭 三个角度
vector dir = set(1,0,0);
matrix mat = ident();
rotate(mat, a, set(0,1,0));
dir *= mat;
vector newpos = @P + dir * f@len;
int newpt = addpoint(0, newpos);
int line = addprim(0, 'polyline', @ptnum, newpt);
//设置属性以便访问
setpointgroup(0, 'end', newpt, 1);
setpointattrib(0, 'len', newpt, f@len * 0.5); //长度每次变短
setpointattrib(0, 'ang', newpt, a);
}
setpointgroup(0, 'end', @ptnum, 0);
③ 类型为Primitives的branching_tree节点Group设为:last,完整代码为,(上面两个代码一样),
float branchang = radians(f@ang); // 分叉角度
float lenratio = chf('lenratio'); // 长度比例
float angratio = chf('angratio'); // 角度比例
float minlen = chf('minlen'); // 最小长度
int div = chi('div');
float seed = chf('seed');
int pts[] = primpoints(0, @primnum);
int pt1 = pts[0];
int pt2 = pts[1];
vector pos1 = point(0, 'P', pt1);
vector pos2 = point(0, 'P', pt2);
vector vaxis = normalize(pos2 - pos1); //水平轴
vector haxis = v@haxis; //垂直轴
float len = distance(pos1, pos2);
float thickness = point(0, 'thickness', pt2);
if(len < minlen){
return;
}
float range = radians(chf('random_h_ang'));
float randang = rand(seed * @primnum + 33.5);
randang = fit01(randang, -range, range);
matrix mat = ident();
rotate(mat, branchang + randang, haxis);
vector npos = pos2;
npos -= pos1;
npos *= mat;
npos *= lenratio;
for(int i=0; i
7、矩形细分与递归
摆烂,但还是记录下,毕竟最后一个了。
eg.①最终结果,
③ 类型为Primitives的sq_subdivision节点代码为,
int ite = detail(1, 'iteration');
int pts[] = primpoints(0, @primnum);
int sw = 1 - i@sw; // switch
float seed = chf('seed') + ite * 43.2 +@primnum * 4.6;
float randval = rand(seed);
float minscale = chf('minscale');
randval = fit01(randval, minscale, 1.0 - minscale);
randval += fit01(noise(seed + @Frame* chf('speed')), -minscale, minscale);
for(int i=0; i<2; i++){
int newprim = addprim(0, 'poly');
setprimattrib(0, 'sw', newprim, sw);
for(int n=0; n