▉只要不认命,没有飞不上枝头赛凤凰的麻雀,哪怕最开始低贱到尘埃里。(凤姐)—每天翻译一篇教程,这就是我写给houdini的情书。【首发于同名公众号:“致houdini的情书”】
█ .《致海子》
今夜我路过你的村庄了 !长满麦子的村庄 密密的火焰 蔓延了三尺三丈 !我不曾听着你的歌 不曾看见你的锋芒 !我知道你的坟头面朝南方 我知道你的坟在乱葬岗上! ——凤姐
词穷liao:
上联:
上班路,疑无路,荆棘路,十字路,葛宇路,高速路,不管真路假路,统统都是路!
下联:
僵尸粉!通心粉!酸辣粉,松花粉!痱子粉!脑残粉!不管白粉黑粉,统统都是粉!
横批:
统统路转粉!
今天看一下:
如何实现一群粒子无中生有随机生长的效果?
这一节要实现的效果
.....
▉今天是42岁第014天周四
这是写给houdini的
第040封“情书”
我是geo流程图
我是solver流程图
我是volumevop流程图
本节需要注意的知识点:
1
函数
1)getpointbbox(0,”static”,min,max); 返回边界框最小最大角的矢量值=min和max
2) (normalize(sample_sphere_uniform(nrandom()))*bbrad);
//sample_sphere_uniform函数=给定一个统一数字在0和1之间,生成一个统一的长度为< 1的矢量。
//nrandom函数=一个更好的伪随机数字生成器,这个脚本产生随机位置,在球上或球内,“
//normalizing函数=确保这个点总在球表面,而不是在球内部。
// *bbrad 最后乘边界框半径,负责扩大这个范围
3)函数volumsamplev (1,0,v@P); //“体积样本矢量volum sample vector”函数看一下当前的值是多少,1是:槽2引入外部的volume进行采样,要对第一个primitive进行采样,它是0;v@P是当前的位置。
2
获得这个增长系统的主要步骤
1)首先创建一个add点。归入静态组
2)第一个pointwrangle设置:这个点通过一次移动获得的周围多个move粒子的位置,id。
/a/粒子"移动步幅"每一步移动距离。
/b/ getpointbbox函数获得static组的min和max
/c/ 进而获得边界框中心点bbcenter=min+max)/2
/d/半径:distance(bbcenter,max)+2* "移动步幅"
/e/ 求move组的现有粒子数量(移动点):npointsgroup(0,"move")
/f/ 求附近可能成为move粒子的数量(目标点):targetnum = int(4 * (bbrad * bbrad) * 3.1415926 * 4000); 单位面积内4000个粒子
/g/ 判断移动点<目标点时:求所有可能目标点的位置,循环次数=目标点-移动点;
/h/ 最后求点id,移入move组,移出static组。
3)第二个pointwrangle设置:检查靠近“静态点”附近的“移动点”在一个概率范围内,把满足条件的移动点,变成静态点。不满足条件的移动到靠近静态点的位置,转变成静态点。
/a/ 通过设置最大距离变量maxdist,在这个范围内,通过nearpoint函数查找附近移动点。
/b/如果找到,又满足随机值小于一个设定的概率,这个点设置为static组,
/c/ 否则如果一个点都没有,则move点可能距离太远,
/d/ 这时又大于一个判断距离的条件时,把那些大于这个距离的点通过 bbcenter + (normalize(sample_sphere_uniform(nrandom()))*bbrad);拉回靠近boundingsphere的附近。再进入下一帧的计算。
4)第三个pointwrangle设置:针对move组对粒子位置+一个随机值;
3
用curlnoise控制粒子增长的随机性
1)首先volume
2)volumevop加入curlnoise。
3)把volumevop连接到solver的槽2
4)在wrangle3里使用函数vector vel = volumsamplev (1,0,v@P); 引入这个vel变量。
5)再把这个变量加入运动点的位置。
接下来
理论部分
问题A:扩散聚集原理是什么
==运行原理==
01)它是电沉积铜形成的原理,这种形状模拟,速度不是很快。它被称为:融合有限聚合!
1)假设我们有两个点:
一个“静态点(static point)”(seed)这个点不能动,就是沉淀物
一个离它一定距离的“移动点(moving point)”
2)开始时,“移动点” 远离“静态点”
3) “移动点”自由随机的选择方向,每一步移动一点点。
4)给定距离内,它检查是否有任何“静态点” 。
5)如果附近没有静态点,该点会再次选择随机方向,移动。
6)如果经过一些步骤,“移动点” 在其附近找到一个“静态点”
7)“移动点”变成一个静态点,并在一个给定的距离,产生另一个移动点。
==问题来了:这种算法非常慢==
这个系统,同时会产生两个点,这些随机产生的点,有一半的几率会靠近“静态点”;
问题B:加快速度的两个技巧
方案1)有一个“移动点”
1)为了防止移动点距离静态点太远,让我们检查它们是否在”静态点边界球体“”外,如果太远,就要花很长时间,
2)如果它们移动得太远,让我们把它们放回靠近边界球外侧的地方。
方案2)多个“移动点”同时漫游
1)为了提高中间一个点碰到“静态点”的几率
2)同时“动态点”数量随着“静态点边界球体”的增大而增多。所以点越来越多,球作为“volume体积”越来越大。
接下来
开始正式制作
使用软件houdini16.5
问题1:如何创建融合有限聚合步骤
1)add1 // 增加一个点
创建2个组,1个“静态点”1个“动态点”
2)group1 //
1)Name:static;
2)Type:points;
3)group2 //
1)Name:move;
2)Type:points;
3)取消Base group选择
两个组:move组中没有点;static组中一个点
=======进入模拟器======
4)solver1 //
首先:创建
“移动点”
4-1):pointwrangle1 //
2)Run over:Detail //只运算一次
a) //首先:声明变量,希望调整步长;就是“移动点”每一步可以移动多远;
floatsteplen = chf(“Step_Length”);
1)暂时Step_Length=0.01
//然后:两个矢量-得到boundingboxs的最大最小值,
vector min max;
// 求“static组”中所有点的bondingbox。
getpointbbox函数作用:得到min和max两个向量值;将两个向量设置为几何边界框的最小和最大角的向量 。
getpointbbox(0,”static”,min,max); //static只关注静态组的边界框。
// 求bondingbox的中心点。赋给一个变量bbcenter
vector bbcenter = (min+max)/2;
// 我们需要的是bounding球,而不是box,所以我们需要的是bounding半径;
测试 // floatbbrad = distance(bbcenter,max);
// 让产生的粒子有一定移动空间:
float bbrad = distance(bbcenter,max) + 2*steplen; //加两个步长
// 我们需要一个整数,告诉我们模拟中已经有的“移动点”的数目。
intnumbermoving = npointsgroup(0,”move”);//告诉我们有多少点移入了这个组。
//定义变成“移动点”的数目;我们称“目标数”它是整数,我们计算sphere区域内,用bounding sphere radius计算这个边界球面积的公式(4*半径平方*PI),
inttargetnum = int(4 * (bbrad*bbrad)* 3.1415926 *4000);//面积乘4000=单位面积内的粒子数目,我们将在模拟中得到更多“移动点”以适应不断增长的结构!
//条件检查;“模拟中移动的点”<“目标数点”
If(numbermoving //我们希望模拟中诞生一些点;for循环, //循环次数<(“目标点数”-“模拟中移动点数”)=应该要移动的点数 for(int i=0; i<(targetnum-numbermoving); i++){ //建一个新的变量:npos点位置,它的中心点跟边界框的是同一个,在半径范围内随机选择一个位置。 // 这个表达式: 1)产生一个点的随机位置(在球上或球内), 2)再normalizing函数,使这个点总在球表面,而不是在球内部。 3)最后乘边界框半径,负责扩大这个范围 4)再加上中心点bbcenter,把随机点移到了边界框位置。最后随机生成了一个位置。 vectornpos = bbcenter + (normalize(sample_sphere_uniform(nrandom()))*bbrad); sample_sphere_uniform函数=给定一个统一数字0和1之间,生成一个统一的长度为< 1的矢量。 //nrandom函数=一个更好的伪随机数字生成器,这个脚本产生随机位置,在球上或球内,“ // 创建新点ID//点纳入move组//点移出static组 intnewpt = addpoint(0, npos); // 创建新点ID setpointgroup(0,”move”,newpt,1);//点纳入move组 setpointgroup(0,”static”,newpt,0);//点移出static组 } 第一次运行: 然后:静态点附近检查移动点 4-2):pointwrangle1 // 1)暂时max_ dist=0.01; 2)stick Probability =1; 3)step Length=0.01; //这里检查是否“移动点”靠近“静态点”建一些变量比如“搜索静态点最大距离” float maxDist = chf(“max_dist”); //为了让视觉更有趣,给每一个粒子的固定概率值,增加一些可能性,不是所有时间都会固定。 floatstickprob = chf(“stick_probability”) // 定义一下步长,作为允许移动的每个粒子的数量, floatsteplen = chf(“step_length”); // 通过getpontbbox求min和max,来获得“静态点”的球形边界框的中心和半径。 vector min,max; getpointbbox(0,”static”,min,max); //返回min和max两个是ge vector bbcenter = (min+max)/2; floatbbrad = distance(bbcenter,max) + 2*steplen; //接下来找:临近点!对于距离“移动点” 一定距离内的点,使用“临近点函数” intnearpt = nearpoint(0,”static”,v@P,maxDist) //v@P=当前点,这就是我们要找为了找出点群static中最接近我们当前点位置的点。 if(nearpt>-1){//如果它什么都没找到它将会返回; 如果找到这个点,分两种情况; 1)如果nrandom随机值< stickprob固定概率值 ,把点移入“static”组; if (nrandom() < stickprob){ setpointgroup(0,”static”,@ptnum,1) ; setpointgroup(0,”move”,@ptnum,0) ; } } 2)否则: else{ //如果附近没有一个点,可能距离太远了; //平方是因为这是计算和标准距离更快的方式,执行速度会更快 if(distance2(bbcenter,v@P)>(bbrad * bbrad )){ //这时粒子偏离的太远,把粒子移到靠近边界框的位置; vectornpos = bbcenter + (normalize(sample_sphere_uniform(nrandom()))*bbrad); //让它位置靠近boundingsphere。 v@P = npos; } } 最后:给点位置+一个随机矢量 //通过“体积样本矢量volum sample vector”看一下当前的值是多少,对槽2引入的volume进行采样,它是1, //我们要对第一个primitive进行零采样它是0;v@P是当前的位置 4-3)pointwrangle3 // 1)暂时max_ dist=0.01; a) //声明一个随机变量,范围是从{0,0,0}到{1,1,1}空间变成{-1,-1,-1}到{1,1,1}空间,nrandom返回0到1之间的随机数,或随机单位向量。 vector step = nrandom()*{2,2,2}-{1,1,1}; //声明调整步长;就是“移动点”每一步可以移动多远; floatsteplen = chf(“Step_Length”); // 把这两个因素加到当前位置上: v@P += step * steplen + vel; //v@P += step * steplen; b)只针对move点运行随机运算; 4)solver1 // 提高sub steps =32 几次运算次数 5)blast1 // group:move 问题2:如何 使用curlnoise控制生长结构随机性 6)volume1 // 1)Rank:vector 2)name:vel 3)size=6*6*6 4)Uniform Sampling Divs=100 7)volumevop1 // 7-1)Bind Export // 1)name:vel 2)type:vector 7-2)curlnoise 1)连接P 2)外置参数 : type, frequence, offset, amplatude, rough,atten,turb 3)连接Bind ===体积切片观察curlnoise的效果=== 8)volumeslice1 9)volumetrail1 1)“槽1”接volumeslice1 2)“槽2”接volumvop1 Vop连接到solver“槽2”移动点时会用到 4-3)pointwrangle3 // Input2连接“槽2” //通过“体积样本矢量volum sample vector”看一下当前的值是多少,对槽2引入的volume进行采样,槽口id是1,我们要对第一个primitive进行零采样它是0;v@P是当前的位置 vector vel = volumsamplev (1,0,v@P); //引入vel变量 vector step = nrandom()*{2,2,2}-{1,1,1}; floatsteplen = chf(“Step_Length”); v@P += step * steplen+ vel; // 注意是“+”号 调整一下vop输出值的范围,vop内 加入 7-3)multiply // 外置参数input2 7)volumevop1//关键数据 1)Input number2=0.01//这相当于输出矢量的步长,太大没效果 问题4:如何缓存&读入模拟文件 7-1)filecache 它会在工程目录下新建geo文件夹 1)文件路径名称:$HIP/geo/$HIPNAME.$OS.$F.bgeo.sc 2)save to disk // 保存模拟数据 3)√load from Disk //可以读入模拟数据 问题5:如何如何控制粒子大小 10) pointwrangle @pscale = 0.01; ==渲染粒子 == 相关准备工作 // 灯光;摄像机;背景板 11) Null命名OUT 12)环境光 13)camera 14)grid // 让grid始终跟随摄像机 勾选 // 渲染引擎 15)Mantra 1)Rendering Engine:Physically basedrendering引擎 2)Limits / Reflect Limit=4;Refract Limit=4;Diffuse Limit=8 // 材质 16)principledshader1// 背景材质Base color:深灰色 17)classicshader1 // 粒子材质Base color:浅色 渲染技巧 1)渲染时点击哪个位置,先渲染 2)右键 可以一直保持渲染完那个区域 3)渲染景深: 13)camera 1)选中camera回车 2)按“Z”键,调节红色的箭头和方块 问题5:如何如何使用红移渲染粒子 1)让grid始终跟随摄像机 18)rslightdome1 1)使用一张HDR贴图 2)Intensity Multiplier=2 2)点击 打开rs渲染引擎 19)Redshift_ROP1 1)IPR面板/ 取消覆盖camera: 2)调整全局光设置: 3)渲染 点击 问题:粒子无法渲染出来 19-1)Redshift_IPR1 1)把Redshift_ROP1拖入Linked ROP中 如何红移替换粒子 20)instance1 1)点击 增加一个rs的OBJ面板 21)Sphere1 1)polygon 2)取消显示 // 使用instance(实例)的好处:提高交互速度 20)instance1 1)Instance面板/Instance object选择sphere1 2)Point Instancing:Full point instancing 20-1)Object_merge 1)Object1选择OUT 粒子被sphere替换 // 材质 22)redshift_vopnet1 // 重命名paper,赋给instance。 22-1)RS_material1 // present:paper // 预设选择纸材质 23)redshift_vopnet2 // 重命名BG,赋给背景 23-1)RS_material1 // 1)diffuse color:深色 2)diffuse roughness=0.3 3)反射weight=0 设置红移景深 1)选中camera点击 2)增加一个Redshift Camera面板,√Enable DOF 3)也可取消camera设置,调节景深 今天就到这儿了,收功 教程翻译自entagma的网络教程 下一节:20170605 VEX in Houdini- Movie Color Visualisation 本文图片全部原创,版权归原作者所有。