分久必合,合久必分,人世间一直都在重复着同一个故事。—每天翻译一篇教程,这就是我写给houdini的情书。
【首发于同名公众号:“致houdini的情书”】 <Entagma>Houdini 2016
彪悍的人生不需要解释:
这个世界,开始都差不太多,后来穷的越穷,富的越富,贫富差距越来越大,最后出现了一个巨无霸!
弱肉抢食,成王败寇的世界里。窃钩者诛、窃国者侯。环顾一下这个世界,每天这种事情都在残酷而真实的上演着。如同下面这个的粒子世界。
这是一个弱肉强食的故事:
一个自定义的粒子系统里所有粒子是如何被一个彪悍的粒子全部吞并的?
这一节要实现的效果.....
▉今天是42岁第002天周六
这是写给houdini的
第028封“情书”
我是geo流程图
我是solver流程图
本节需要注意的知识点:
1 创建自定义粒子的主要步骤
1)首先scatter撒点。
2)pointwrangle自定义粒子的4个要变量
a)粒子加速度a; b)粒子大小pscale;
c)粒子质量mass;
d)自发光属性emit;
3)进入solver结算器:三个pointwrangle
a)第一个wrangle判断粒子是否相交;如果相交删掉小的粒子。套用“加速度公式”。
b)第二个wrangle计算粒子之间的引力,推算出粒子的加速度;
c)第三个wrangle,根据加速度更新粒子的信息(1.位置。2.加速度。3.自发光)
2 如何使用自定义的emit控制粒子自发光属性
1)建议使用principledshader材质,classicshader无法出现辉光效果。参数Emission面板下勾选Enable Emission
2)右键材质节点选择“允许编辑内容”进入内部
3)建立bind节点,name:emit。
4)连接到emit_illum输入槽上
5)在copy节点,继承属性里输入emit。
接下来
理论部分
DIY粒子系统
问题1:相关的物理学数学是什么
(一)首先是转换公式
1) 体积(volume)与半径(Radius)的关系
计算球体体积的方法
粒子中主要处理的就是球体的末端(也就是半径)
所以上面就是粒子系统要用的公式
(二)其次是牛顿万有引力定律
1)公式:计算两个相隔物体之间的力大小:
a)距离=距离是从A的中心指向B的中心的向量
b)矢量长度乘标准化方向矢量替换万有引力定律的距离 后公式:
c)为了获得矢量方向最后需要知道计算产生的加速度
以上是帮助我们建立物理粒子系统的公式
问题2:实际创建自定义粒子的步骤
01两个粒子
02 三个变量
1)一个位置矢量;
2)一个加速度矢量a(加速度);
3)一个半径标量pscale(粒子大小)
03 开始模拟
1
首先
使用牛顿定律更新加速度a
a)首先计算“引力”(两个粒子之间 以及与所有粒子之间的引力)
b)然后把它们放在一起,更新产生的粒子加速度向量anew
2
接着
a)更新粒子位置(并沿着新的加速度矢量位置移动它们)
b)检查粒子是否相交: 如果相交:删掉小的粒子!
3
最后
更新“剩余的粒子的加速度” (通过将 “先前的加速度矢量” 与 “单个粒子质量” “成比例地” 加在一起)
总结自定义粒子步骤
1)更新a=加速度
2)更新粒子p,沿a移动它们
3)检查;如果相交,删除两者中的小粒子。
4)更新剩下的粒子“加速度”,按照两个粒子的质量成比例的把“加速度”加在一起
接下来
开始正式制作
使用软件houdini16.0.633
1 创建初始粒子
1)circle1
1) Zx轴向;10*10
2)scatter1:
a) Count=1000
b) Relax Iteration=128;
2 初始化粒子变量
3)pointwrangle1:
//1//粒子速度
f@emit = 0.0; //发射变量为后面自发光初始化准备
v@a = {0,0,0}; //为加速度变量初始化
//2// 粒子大小
f@pscale = rand(@ptnum + chi("seed"));//创建一个随机的pscale大小变量,为了加速粒子运动seed作为随机因子
f@pscale *= 0.1; // 降低吸收粒子速度
//3//粒子质量
f@mass = pow(@pscale, 3) * 4.18879;
计算体积公式:
1)
2)提前算出4/3*PI=4.18879
3 增加粒子间距
在进入粒子系统之前,每个粒子被赋予不同的pscale值,所以当在它们身上克隆sphere,它们可能会相交,
4)Point Relex 1
1) Max Iterations=256
2) Point Radius Scale=1.5; //增大半径
3) 勾选Relax in 3D Space;
5)solver:
进入solver内部:建立三个wrangle:
首先是判断是否碰撞,如果有碰撞输出碰撞后的质量,加速度,自发光等变量;
然后根据这些变量求得引力,进而推算出新的加速度a;
最后根据加速度a,更新粒子的位置,加速度,自发光等变量。
问题3:如何得到碰撞后的粒子变量参数
5-1)pointwrangle1:
pcfind_radius函数:
//----------首先pcfind_radius函数寻找相交点------------
//使用pcfind_radius函数寻找相交点;这是个数组
int closept[] = pcfind_radius(0,“P”,“pscale”,1.0,v@P,@pscale,2); //0输入槽;在P通道上工作;
0:输入槽;在P通道上工作;"pscale"粒子大小属性;1.0是粒子半径 ;v@P搜索范围内点的当前位置;@pscale是搜寻范围;最后是范围内点的数量;
如果给定的半径内点是相交的,就会考虑点的大小,不是在无限小的点上工作;而是在copy的sphere上,
这个函数的功能就是在一定范围内探测sphere的交点。这正是粒子系统需要的。
//-----接下来判断是否找到了相交点----
if(len(closept)>1){ //数组的长度大于1时,数组的第一个位置上查找到的点是它自己 。所以数组第二个位置是碰撞点,
//---索引=1的粒子的位置,质量,加速度----
vector closepos = point(0,“P”,closept[1]); //首先看一下碰撞粒子的位置,
float closemass = point(0,“pscale”,closept[1]); //求碰撞粒子的质量;
float colsea = point(0,“a”,closept[1]); //同样引入碰撞粒子的加速度
//碰撞后的矢量加速度a,用一个公式表示这种非弹性碰撞:两个粒子矢量加速度的合并值=两粒子质量*加速度的和/两粒子质量之和。
vector asum = (@mass * v@a + closemass*closea)/(@mass+colsemass); //@mass 当前粒子的质量;v@a 当前粒子的加速度 ;
------------------------------------
//如果粒子碰撞,计算数值,产生加速度,删除小的粒子;通过比较质量,判断哪个粒子更大。
@mass:索引=0的质量:closemass:索引=1的质量:
//------如果 @mass > closemass------
if(@mass > closemass){
removepoint(0,closept[1]);
//更新索引=0的粒子的质量和加速度
f@mass += closemass;
v@a += asum;
}
//------否则 @mass <= closemass------
else{
float masssum = f@mass + closemass; //删除粒子之前,重新计算一下质量之和;
removepoint(0,closept[0]); //移走索引=0的粒子;
setpointattrib(0,"mass",closept[1],masssum); //设置索引=1的粒子的质量给mass质量通道
setpointattrib(0,"a",closept[1],asum); //设置索引=1的粒子的质量给a加速度通道
setpointattrib(0,"emit",closept[1],1.0); //设置索引=1的粒子的自发光给emit通道
}
问题4:如何得到万有引力&新的加速度
5)pointwrangle2
//-------------接下来计算粒子之间的引力&加速度-----------
vector a = @a; //粒子加速度a赋值给变量a;以此调用加速度a的值
vector dirA = {0,0,0}; //初始化方向矢量
vector ndirA = a; //初始化新的方向矢量
//找到其他的点,那里没有我的粒子系统,然后通过mass和a,计算影响当前粒子和这个粒子之间的引力,
for(int i=0;i<@numpt;i++){
if(i != @ptnum){ //如果碰撞粒子id 不等于当前粒子的id
dirA = v@P - point(0,"P",i); //当前粒子到碰撞粒子的方向矢量
float r = length(dirA); //粒子间距;
ndirA = normalize(dirA); //标准化dirA,万有引力公式会用到。
//另外两个粒子的质量
float massA = @mass;
float massB = point(0,"mass",i);
//引力公式 = (质量相乘/距离平方)*方向*重力常数
vector force = ((massA*massB)/pow(r,2))*ndirA*-0.1;
//粒子A的加速度;
vector aA = force/massA;
//最终当前粒子加速度a
a +=aA;
}
}
//因此,在我们运行了所有这些并遍历所有其他点之后,我们可以将生成的新加速度向量写回我们的point属性上
v@a = a;
问题5:最后根据新的加速度如何更新粒子信息
//--------更新粒子的位置----------
v@P += v@a; //使用前面得到的加速度a更新当前粒子的位置
v@a *= 0.99;//设置阻尼,没有碰到粒子,会减速
//---------更新粒子的半径---------
//调用粒子半径与质量关系的公式
//使用cbrt次方根函数
f@pscale = cbrt(f@mass/4.1889);
//---------更新粒子的自发光---------
f@emit -= 0.025;
f@emit = clamp(f@emit,0,1); //clamp函数返回夹在min和max之间的值
接下来copy sphere给粒子,加灯光,渲染器 准备渲染。
6)copy to point
7)sphere
8)grid 地面
9)环境光 :加hdr贴图
材质部分:
10)classicshader :给地面
1) 漫反射通道color :HVS:v=0.1
2) 反射通道;intensity=0.2
3) Routhness粗糙度=0.5;
11)mantra渲染
1) 渲染引擎Physically…
2) limits:反射=4; 折射=4; 漫反射=4
12)camera
1) translate=0*50*0 ;
2) Rotate=-90*0*0
问题6:如何用自定义emit属性控制粒子自发光强度
11)principleshader :这个材质节点有辉光效果。classicshader没有产生
1) 参数面板:勾选Enable Emission
2) 右键
进入内部
3)建立blind节点 name:emit
4)连接emit_illum槽口。
6)copy to points
1) to point:输入emit
产生了辉光,根据每个粒子的emit的值控制亮度
今天就到这儿了,收功
教程翻译自entagma的网络教程
下一节:20161226 Naive Path Finding路径发现
本文图片全部原创,版权归原作者所有。