原视频:https://www.youtube.com/playlist?list=PLzRzqTjuGIDhiXsP0hN3qBxAZ6lkVfGDI
Bili:Houdini最强VEX算法教程 - VEX for Algorithmic Design_哔哩哔哩_bilibili
Houdini版本:19.5
如有错误,可在评论区指正。
1、本章主要讲引力相关
万有引力公式:
本章主要是根据引力相关进行延伸、拓展等,(l 为距离,direction为运动的方向),
还有个关于万有引力的相关重要知识点: 引力的大小跟这两个物体的质量的乘积成正比,跟它们的距离的二次方成反比。
2、引力
本小节来实现下引力,总体难度不大,原理如下图,
eg.①先上结果,主要是根据上面,
②节点连接及设置,更多的是对参数进行设置、调试,
③补充,解算器solver内的attractor_force节点代码如下,
float massM = f@mass;
float massA = point(1, 'mass', 0);
vector attractorPos = point(1, 'P', 0);
float l = distance(@P, attractorPos);
float g = point(1, 'gravitation', 0);
vector v = normalize(attractorPos - @P); //运动方向
float s = massM * massA * g / (l * l);
s= clamp(s, chf('minforce'), chf('maxforce')); //谨防出现无穷大或无穷小的力
vector force = v * s;
v@vel += force;
v@vel = normalize(v@vel) * min(length(v@vel), chf('maxspeed')); //对速度进行限制
v@P += v@vel;
3、多重引力
多个引力体与多个被吸引体。
eg.①先上结果,案例与上面差不多,
②节点连接及设置,可对参数进行设置、调试,看看不同参数的结果,
③补充,解算器solver内的attractor_force节点代码如下,
float massM = f@mass;
//该点受到不同引力体吸引的的总引力
vector totalForce = set(0,0,0);
for(int i=0; i<npoints(1); i++){
float massA = point(1, 'mass', i);
vector attractorPos = point(1, 'P', i);
float l = distance(@P, attractorPos);
float g = point(1, 'gravitation', i);
vector v = normalize(attractorPos - @P); //运动方向
float s = massM * massA * g / (l * l);
s= clamp(s, chf('minforce'), chf('maxforce')); //谨防出现无穷大或无穷小的力
vector force = v * s;
totalForce += force;
}
v@vel += totalForce;
v@vel = normalize(v@vel) * min(length(v@vel), chf('maxspeed')); //对速度进行限制
v@P += v@vel;
4、引力与朝向
与前面相同,这次设置了法线(@N= 速度),以及使引力体动起来。
eg.①先上结果,
②节点连接及设置,
③ 补充,两个解算器内的代码如下, attractor_force节点
//solver5节点内的代码:引力体对象在范围内随机运动
vector pos = @P * 0.01;
vector4 pos4 = set(pos.x, pos.y, pos.z, @Time);
vector f1 = curlnoise(pos4);
vector f2 = set(0,0,0);
//在体积外层,给一个往内的力,把它拉回来
float val = volumesample(1, 'surface', @P);
if(val>0){
f2 = -volumegradient(1, 'surface', @P);
}
vector force = (f1 + f2) * chf('k');
v@vel += force;
v@vel= normalize(v@vel) * min(length(v@vel), chf('maxvel'));
@P += v@vel;
// solver4内的attractor_force节点代码
float massM = f@mass;
//该点受到不同引力体吸引的的总引力
vector totalForce = set(0,0,0);
for(int i=0; i<npoints(1); i++){
float massA = point(1, 'mass', i);
vector attractorPos = point(1, 'P', i);
float l = distance(@P, attractorPos);
float g = point(1, 'gravitation', i);
vector v = normalize(attractorPos - @P); //运动方向
float s = massM * massA * g / (l * l);
s= clamp(s, chf('minforce'), chf('maxforce')); //谨防出现无穷大或无穷小的力
vector force = v * s;
totalForce += force;
}
v@vel += totalForce;
v@vel = normalize(v@vel) * min(length(v@vel), chf('maxspeed')); //对速度进行限制
v@P += v@vel;
v@N = normalize(v@vel);
5、角向力/旋转力
以力作角度,绕引力体做环绕运动。原理大概如下,
eg.①老规矩,先上结果,
② 节点连接及设置,
③补充,解算器solver内的angular_force节点代码如下,
vector posC = point(1, 'P', 0);
float massC = point(1, 'mass', 0);
float massM = f@mass;
float g = point(1, 'gravitation', 0);
float l = distance(@P, posC);
float f = massM * massC * g / (l * l);
f = min(f, chf('maxforce'));
f@ang += f;
f@ang = min(f@ang, chf('maxang'));
matrix mat = ident();
rotate(mat, f@ang, set(0,1,0));
@P -= posC; //要旋转,先归位至轴点。否则默认以(0,0,0)为轴点旋转
@P *= mat;
@P += posC;
6、自转与角运动
与【5的例子】类似,对被吸引的对象添加自转运动,
关于自转,只关注自身,其它的力(如引力)不管,原理大概如下,
eg.①结果略
② 直接使用【5、角向力/旋转力】的案例,仅对修改部分进行标注,节点连接及设置如下,
③补充,解算器solver内的angular_motion节点代码如下,
float mass = f@mass;
float g = f@gravitation; //一个自定义力,或者说是系数
float force = mass * g;
force = min(force, chf('maxforce'));
f@angM += force;
f@angM = min(f@angM, chf('maxang'));
matrix mat = ident();
rotate(mat, f@angM, set(0,1,0));
v@N *= mat;
7、单摆运动
原理大概如下,
eg.在Houdini中实现单摆运动,
①节点连接及设置如下,
②补充,完整代码如下,
f@ang = radians(chf('ang')); // 角度随意
vector axis = set(0,0,1);
matrix mat = ident();
rotate(mat, f@ang, axis);
@P *= mat;
f@mass = chf('mass'); // 角度随意
f@pscale = f@mass * 0.2; // 尺寸随意
float l = prim(0, 'perimeter', 0);
float g = chf('gravity'); //设为0.5/任意值
float mass = f@mass;
float force = -g * mass * sin(f@ang) / l;
f@vel += force;
f@vel *= chf('damping'); //衰减系数(摩擦力之类),设为0.995/任意值
f@ang += f@vel;
vector dir = set(0, -1, 0);
matrix mat = ident();
rotate(mat, f@ang, set(0,0,1));
dir *= mat;
@P = dir * l;
③结果略
8、多对象单摆运动
与【7、单摆运动】差不多,这次使用For-each-number循环生成多条单摆线,
eg.①节点连接及设置如下,
②完整代码如下,
// 解算器Solver内代码节点的代码
//ball属性的点,代码执行
int prim = pointprims(0, @ptnum)[0]; //该点所在的primitive
int pivotpt = primpoints(0, prim)[0]; //该primitive的第一个点作为轴点
vector pivotPos = point(0, 'P', pivotpt); //轴点位置
float l = prim(0, 'perimeter', prim);
float g = chf('gravity'); //设为0.5/任意值
float mass = f@mass;
float force = -g * mass * sin(f@ang) / l;
f@vel += force;
f@vel *= chf('damping'); //衰减系数(摩擦力之类),设为0.995/任意值
f@ang += f@vel;
vector dir = set(0, -1, 0);
matrix mat = ident();
rotate(mat, f@ang, set(0,0,1));
dir *= mat;
@P = pivotPos + dir * l;
// setup节点内代码,循环生成多条线
int ite = detail(1, 'iteration');
int numite = detail(1, 'numiterations');
@P.z = ite;
float minlen = chf('minlen');
float maxlen = chf('maxlen');
float y = fit(ite, 0, numite-1, 0, $PI * 4);
y = -fit11(sin(y), minlen, maxlen);
if(inpointgroup(0, 'ball', @ptnum) == 1){ //保险起见,加多ball做判断条件
@P.y = y;
}
9、弹力
具有约束性的弹力,就像单摆加了根弹力绳,
受力分析及公式推导大概如下 ,
eg.①在Houdini里实现上面动图的效果,节点连接及设置如下,
②补充,完整代码如下,
// init6 节点代码
f@mass = chf('amss'); //参数设为1或随意
f@targetlength = chf('target'); //参数设为0.5或随意
f@pscale = f@mass * 0.25;
v@vel = set(0,0,0);
//解算器内的spring_force节点代码
vector pivotPos = point(0, 'P', 0);
vector v = normalize(pivotPos - @P);
float l = distance(pivotPos, @P);
float tl = f@targetlength;
float diffl = l - tl;
float n = chf('stiffness'); // "绳子"的弹性系数
vector f1 = v * f@mass * (diffl * diffl) * diffl / abs(diffl) * n ;
f1 = normalize(f1) * min(length(f1), chf('maxforce1'));
vector f2 = set(0, -1, 0) * chf('gravity') * f@mass;
v@vel += f1;
v@vel += f2;
v@vel *= chf('dampling'); //摩擦系数
@P += v@vel;
③可以去试试调下参数,感受各个参数对结果的影响。
10、弹力“链”
这次是实现下面这种效果,
受力分析及公式推导大概如下 ,
eg.①在Houdini里实现上面动图的效果,节点连接及设置如下,
②补充,完整代码如下,
// init7 节点代码,节点类型为Points
if(@ptnum == 0 || @ptnum == npoints(0) - 1){
//后面用作固定首末两个点
setpointgroup(0, 'pin', @ptnum, 1);
}
f@mass = chf('mass'); //设为0.1或随意
v@vel = set(0,0,0);
// init_prim 节点代码,类型为Primitives
f@targetlength = f@perimeter;
// spring_force节点代码,节点类型为Primitives
int pts[] = primpoints(0, @primnum);
//每两个点之间的弹力
for(int i=0; i<len(pts); i++){
int pt1 = pts[i];
int pt2 = pts[(i+1) % len(pts)];
vector pos1 = point(0, 'P', pt1);
vector pos2 = point(0, 'P', pt2);
float mass1 = point(0, 'mass', pt1);
float mass2 = point(0, 'mass', pt2);
vector v = normalize(pos2 - pos1);
float l = distance(pos1, pos2);
float tl = f@targetlength;
float diffl = l - tl;
float n = chf('stiffness');
vector force = v * (diffl * diffl) * (diffl / abs(diffl)) * n;// *mass1 * mass2 *
force = normalize(force) * min(length(force), chf('maxforce'));
setpointattrib(0, 'vel', pt1, force, 'add');
}
// gravity_force 节点代码,类型为Points
vector force = set(0, -1, 0) * chf('gravity');
v@vel += force * f@mass;
// update_pos 节点代码,节点类型为Points
if(inpointgroup(0, 'pin', @ptnum) == 0){
//非首末两个点,位置更新
v@vel *= chf('dampling'); //摩擦系数
@P += v@vel;
}else if(@ptnum == 0){ //第一个点,位置更新
@P = point(1, 'P', 0);
}
没有又找不着翻译,不能倍速看,很烦,只能啃英语生番原速看…