VEX 案例
一.procedural melting程序化熔化
1.创建volume
1.使用[ isooffset ]转化为volume
2.使用[ volumeresie ]调整volume边界

使用[ bound ]节点,[ getbbox_size() ],[ geobbox_center() ]函数获取边界和中心位置信息.

3.使用[ volume ]创建volume,查看范围

2.solver

1.使用 @ix,@iy,@iz获取volume每个体素对应的索引 index
2.使用[ volumeindex() ]检索对应index的体素值
这里获取每个体素y+1,即上面一个体素的值,如果上面的体素值更大则取代当前体素的值

实现volume向下流动的效果
3.添加并上 当噪波小于阈值的条件。噪波使用vector4作为输入(位置加上时间@Frame)

4.设置地面
当@iy,即y方向索引小于floor值时
获取@ix+1,对应索引的体素位置,计算其到当前体素位置的距离,以此作为半径
设置分辨率,则循环对应的次数,使用每次的角度结合三角函数得到新的位置。
再转换为对应的索引,并检索其值,比较其值,当前值小于则设置为新的值。

二.程序化细胞分裂
1.创建点,设置属性基础“life”
2.slover 段1 每个点的扩散
1.搜索每个点的所有范围内的近点(依据最大搜索距离“maxDist”)
2.遍历近点,获取周围的所有近点(==去掉本身==)的位置,计算其指向当前点的==方向向量“dir”==,计算其到当前点的距离==“dist”==,将距离映射1-0(距离越远影响越小)作为影响因子“mult”,使方向乘以影响因子“mult”,再将其==累加存储到“val”==。
3.设置“count”计数有多少个近点,以此除以“vel”(加权操作)。
4.设置vel乘以“speed”,控制点扩散速度
5.更新每个点位置。
此段即计算每个点被周围近点排斥,直到当前点位置移动到超出“maxdist”,即超出最大搜索范围,此时由于周围无近点,则“vel”为0
3.solver 段2 增加新的点(分裂点)
1.设置条件:
1.当前点的生命值"life"(每个点初始设置为0)大于随机生命值"rdlife"(由@P,@ptnum, @Frame共同产生) .再将其映射到设定的"min/maxlife"区间,使得每个点在给定区间内发生分裂.
2.点数小于设定值"maxPt"(点数过多则不再发生分裂).
3.最小距离(即最近的近点距离)大于最大距离(即搜索距离)的0.5. 即设置在搜索距离的一半以内没有近点(避免过于拥挤).
最小距离"minDist"在近点循环中求出.使用比较法
2.计算分裂新点的位置
1.分裂点的方向以"vel"向量为基础,即向着远离当前点的所有近点的方向(向团体以外扩张).
2.使用[ rand_sphere_uniform() ]获取随机方向的向量(设置乘以0.25,即占四分之一的权重)加到偏移量"offset"中.
3.再设置偏移量为搜索距离"maxDist"的0.01.
3.设置新点,设置新点"life"为0,分裂之后设置当前点"life"为0(重新计时).
4.再设置"life"自加.更新生命值.
4.可视化
1.将点转化为VDB,设置point radius(细胞半径) 一般小于最大搜索距离,设置voxel size要小于半径

2.平滑之后转换为polygon.
3.对于内部的点同样其半径要小于细胞半径

5.效果
三. 反应扩散 reaction diffusion
关于拉普拉斯算子:是==二阶微分算子==,为梯度(直接作用于标量场,得到的梯度是矢量场)的散度(点乘矢量场,得到的散度是标量场)
拉普拉斯算子表示的是 ==与周围平均值的差距==.

1.反应扩散原理
模拟两种虚拟的化学物质


条件与公式解释:
1.原本具有一定浓度的A,B物质.
2.==扩散"diffusion"== A,B都会扩散,A扩散的更快.
扩散部分:扩散速率乘以浓度的二阶微分(拉普拉斯算子,得到浓度与周围浓度平均值的差,即浓度的梯度的散度).当周围的浓度更高时(其得到的散度大于0),则扩散的慢(由高浓度流向低浓度),当前位置浓度增加.
这里"源"与"汇"与散度的定义相反,是因为浓度的梯度是由低浓度指向高浓度.那么散度上,低浓度位置则是一个"源"(大于0).扩散反应中则作为"汇",周围的浓度流入,该点浓度增加.
以其梯度的散度理解时:浓度的梯度由低浓度指向高浓度,其散度在低浓度则为"源"(向外),大于0.
所以拉普拉斯算子衡量了当前位置与周围环境的平均浓度差异.当其 > 0时,表示当前点低于周围平均浓度.周围物质则向该点流入
3. A以给定的==送料"Feed"==速率f,增加浓度; B以给定的==杀死"Kill"==速率,减小浓度.
给定速率f/k与浓度成比例
4.==反应"reaction"==,两个B将一个A转化为B(以A为食物繁殖).
==反应速率 与 反应物浓度的乘积 成正比==
质量作用定理
2.VEX
1.初始条件设置.
设置初始的A,B浓度,f和k值.
2.按距离与总距离之比计算 周围点的权重.
保存属性.
3.solver 段1:
获取属性

4.计算"reaction"反应项,计算"diffusion"扩散项.
这里的扩散项:使用周围点浓度与距离权重的乘积(注意减去该点的自身的浓度).
5.计算最终浓度值,保存属性

6.可视化,设置颜色
3.结果
三.导弹追踪(boids系统)
1.使用噪波生成随机的连续路径
1.这里设置seed值每次循环增加一个较小的值,使其产生的噪波连续,再新的位置添加点

2.使用[ add ]连成为曲线,使用[ orientationalonecurve ]获取"up"和tangent值"N"

2.使目标物体沿曲线移动.这里使用[ primuv() ]函数
1.使用[ primuv() ]函数获取对应uv位置的属性的插值
2.再设置新的点,设置新点的属性.
3.运行在prim,转换为curve之后,只有一个prim
4.为发射器设置朝向


2.solver
这里使用23位置输入的原因在于,只保留在solver中生成的点作为输出

1.设置rocket 位置更新规则
运行在“rocket”组,此时组还未建立,在后面创建组“rocket”,这里的先后顺序并无影响,由于设置的每5帧产生一个rocket,所以group将在第5帧产生。此时再更新rocket的速度

初始情况:可以只设置rocket点的方向(指向目标点),设置加速度作为力,更新速度和位置。
运行于rocket组的每一个点
2.创建rocket点(使用detail只运行一次)
读取输入2的点数(circle的点数)
每多少帧产生一个rocket点(使用取余),再与点数取余(获取circle的点索引,依此循环),设置新的点和属性。

3.只设置加速度容易过调,这里设置最大速度限制
4.设置分离力,使rocket之间相互远离
这里使用近点函数,使其远离周围的点
5.设置爆炸点,当距离过近或者“life”清零时将点重新分组以作处理

四.加权最短路径增长weighted shortest path growth
1.初始设置
1.添加字体,打开text attribute。
textindex 属性:由于我这里加了空格(也算),所以是0,2,4
textsymbol属性:则是记录的字母对应的ASCII码值


2.设置point法线,使用[connectivity] 为prim设置 class 属性

3.使用lab工具中的[straight_skeleton_2D]设置字体形状的骨骼

4.使用sort将prim按照X轴排序.

5.设置[for_each_primtive],以"calss" 作为piece attribute.以此保留每一个字母的第一个prims

6.选取每一个prim中的靠左边点(x更小)作为起点.
这里分别 获取每个prim的点列表,获取第一个点和最后一个点的位置,比较谁的x更小,以此作为起点添加新点,再设置属性(将"class","textindex"从prim属性转移到点属性),设置分组为"start".删除原prim


2.scatter point 散布目标点
1.设置isooffset分辨率,这里使用第一个输入的bbox(边界值)

2.设置法线,从geo转移属性到point,这里使用[xyzdist()]函数,寻找到最近几何表面的位置.得到prim和uv,再使用[primuv()]函数在得到的位置插值属性.以此计算最近表面点的N法线和位置P,计算每个点指向近点的向量与法线向量点积,若是小于0,则表示此点在几何表面之外,以此剔除外部的点.
将点对应prim的属性"class"和"textindex"转移到点.

3.使用随机值选取一部分点作为"goal"目标组

3.最短路径算法
1.寻找每个点的近点(这里搜索两个点,但其包含本身,所以只有一个近点),计算到近点的距离.并保存为属性.(==这一步后续第6步才用到,可以放到后面==)
这里不使用[ nearpoint() ],因为其只找一个点这里会找到本身(更适于寻找单纯位置的近点而不是点的近点.使用[ nearpoints() ]可以找到除本身以外的其他近点.
使用[ attributepromote ]函数计算其最大值并保存到detail.
A

2.计算骨骼中每个点到==起点的近点==的距离.
1.这里先使用[ findattribval() ]函数寻找与每个点"class"相同的起点(每一个字母(class)对应一个起点.).从输入2中
2.获取该起点的位置.
3.寻找每个起点的近点(其实位置相同,就是本身,由于这里在上一步设置起点时从原骨骼所有点中剥离).==为了获得对应起点在骨骼中的ptnum编号==,以用来计算距离.
4.使用[ surfacedistance() ]函数计算每个点到近点(起点)的距离.第二个参数使用[ itoa() ]函数将近点编号转换为string类型,得到最近点的编号cpt,"edge"指的是测量距离的方法,"edge"或者"surface".

3.计算最短距离"closestdist"和"edgedist"属性


1.使用[ xyzdist() ]函数计算每个点到骨骼上的指定"class"prim组(即每个字母骨骼)中的最近距离.这里第二个参数(string类型)使用表达式,即与当前点"class"相同的组中.由此计算的=="closestdist"属性,每个点到骨骼的距离==

2."edgedist"则是由之前计算的骨骼上每个点到起点的距离"d"属性转换到点上.这里使用[ primuv() ]函数读取每个点到骨骼上最近的位置的"d"值作为"edgedist"属性.

4.将上述两个属性使用[ attributepromote ]计算最大值到detail.

5.将上述两个属性映射到0-1,以方便计算"weight"属性.

6.生成network.网络(可将第1步迁移到这里)
1.使用之前计算的"neardist"作为最大距离,即每个点搜索一个近点的最大距离,保证每个点至少有一个近点.这里加一个小值,如果刚好等于最大搜索距离,则至少有一个点刚好在边界搜索不到近点.
2.同样使用[ nearpoints() ]函数,目标点组设置为"class"相同.
3.对于每个近点,如果当前点编号更小,则连接成线.这是为==防止重复==,每个点连接编号更大的点,单向连接.



7.使用[ findshortpath ]寻找最短路径.
即寻找每个起点到每个终点的最短路径

4.生长动画设置
1.可以使用[carve]节点,但效率较低.这里使用VEX方法
头文件位置,使用[ adjustPrimLength() ]函数.
第三四个参数,当前prim的长度,和目标长度.使用[ measure ]测量

5.规格化closestdist
1.规格化closestdist,计算点到骨骼最近点的距离,再将"close"和"closestdist"属性promote到prim,再计算每个class 的"closestdist"最大值


2.规格化,设置颜色


6.基础信息计算 (计算maxcount)
注意[resample]节点,其" resample by polygon edge "选项,即保留多边形的顶点,==每个prim的每个边会独立采样==.如果在这里使用[fuse]节点,其"fuse snapped points"融合断裂的点会将同一位置的不同点融合,使用[ resample ]节点又可以生成这些点.

1.==计算每个点(或者说位置)在多少个prim中存在==,需要先使用fuse,否则都为1(即每个点都只存在于一个prim中)

2.使用[attribute promote] 计算count的最大值,计算"class"(每个字母)的"count"最大值.
3.计算总的"count"最大值
4.再将"maxcount"属性复制到到每个起点.
7.设置pscale

1.以每个字母的"count"作为pscale数据来源,将其clamp到1-最大值(避免末端太小)再除以最大值,使范围在0-1.
2.再乘以(1-curveu),以curveu作为影响因素.
3.由于变化太大(pscale曲线曲率太大),这里使用[ pow ]降低曲率,使其变化的更加平缓.
五.飞翔的脊柱 Flying spine
1.初始状态设置
1.copy to points,设置点法线


2.设置bend弯曲,对于每个prims,以起点指向终点向量和法线向量的叉乘为轴axis,设置最大角度(每个prim乘以随机值,注意这里使用@P,获取的是prim的中点位置,每个prim的每个点都是一样,所以即使这里在循环中遍历prims的所有点,但是每个点的随机值是一样的,即每个prim的每个点的旋转角度都是相同的。若要为每个点设置不同的旋转值,则海需要加上i,作为rand函数的种子)。

3.这里要设置让每个点旋转都不一样,可以通过控制中心位置的offset。每个点在旋转之前需要先移动坐标系,即以prim的中点(cen,@P)为参考。
在循环遍历prim的每一个点之前,为每个prim的cen点设置一个偏移量,以保证每个prim旋转中心也不同(影响不大其实)。
在循环中,再在cen位置加上noise(此时以“pos”属性,即每个prim中每个点位置为种子,为每个点的旋转中心都生成不同的偏移量。)

2.solver
1.移动“head”头部点。
设置vector4,以“id”属性随机,再加上位置,设置时间“Frame”,作为curlnoise的种植。以此随机移动“head”点。
2.让其他点跟随“head”点移动
1.运行于每一个prim,先获取prim中ptnum列表,获取前一个移动了的点位置(初始状态是平pts[0],即"head"点.后续在循环中替换该点)
2.循环遍历每个点(除去第一个"head"点,他已经移动过了)
3.获取要移动的点"m_pt",和前一个点"p_pt",获取这两个点的原始位置(从输入1中获取)
4.计算原始这两个点的距离.
5.获取要移动的点的当前位置,计算由前一个点指向要移动点的方向,再以此方向乘以原始两点距离获得要移动点的新位置.
6.将新的这个位置设置为上一个点位置.(以进入下一次循环),设置当前要移动点的位置属性.

3.设置spine形状.


使用三角函数依据高度缩放侧边形状.
将高度@P.y映射到0-1,再以其作为角度0-2PI,以此作为cos值,将cos值从-1 -- 1==映射到1-0==(这样映射使得高度由-0.5 到 0.5,对应从0 到 1 再到 0.即需要保证中间可以被变化,两边比例不变.)
以此乘以x,z值.放缩中间的半径粗细

再以1/$SIZEY,缩放,使其y轴为1.以便于后续使用pscale控制每个关节的大小

2.copy到线
1.先设置pscale,使用[ convertline ]将每个prim的每条线段都转化为prim(此节点生成的"restlength"属性 作为"pscale").
2.结果如图,还需要设置"N",来指使方向
3.设置方向"N",以每个prim的两点指向作为"dir".


4.设置翅膀

1.设置基础形状

2.注意再solver中最后的[ orientalonecurve ]不再生成up,否则up翻转变化过快.
3.去点端点
4.先设置"N"在侧边的摆动
这里原本的"N"是切线,所以设置up以切线为轴随时间偏转,在使用"up"与"N"叉乘获得新的"N",作为对齐翅膀的方向.
5.在原位位置生成新的点,并设置其"N"为负的[ reflect ],获得另一边的"N".设置"pscale"属性,"id"属性."up"属性保持不变.
5.效果如图

六.湍流变换 turbulence morphing
1.基础设置和原理
1.按照几何体的高度(@P.y)映射到1-(设定帧范围,)作为偏移值"offset",即设定从上到下,依此偏移多少帧.(这里设定60帧,即最下面的点的"offset"值为60,其60帧再进行操作)
2.将当前帧(@Frame)从 offset(这里从上到下的点"offset"值依此变大) 到 最大帧减去偏移帧范围(也可以不减),映射到0-1.使用fit函数时超出范围则映射为边界值.所以在当前帧到达每个点的"offset"值之前都为0.==这里的f即是每个点根据当前帧从起始帧"offset"到结束帧映射到0-1.==
对应于越上面的点,"offset"值越小,其映射的原始范围越大(offset-$FEND),越早开始移动,且变化缓慢(范围更大比如最上面的点从1-240帧映射到0-1),都是同样的终点,越后面的点"offset"值越大,其开始的值越晚(比如最下面的点从60-240帧映射到0-1),移动迅速.

2.增加细节,设置旋转
1.以"f"乘以2PI乘以圈数作为旋转角度.旋转@P.
2.给"offset"值增加随机值,使其旋转时不过于整齐

3.为旋转轴"axis"添加噪波.
4.结合第二个几何体做变换.
由于两个几何体点数相同,这里可以读取到另一个几何体的所有点位置.同样获取其y轴最值并映射.将新的偏差值"noffset"加到f的起始范围(这里会使两个几何体的每个点映射的正帧围大小一样.比如同样是最上面的点,其偏差值都是1,则其f值都是由当前帧从1--180帧到0-1的映射,最下面的点的f则是当前帧从60--(180+60)帧 到0-1的映射).
另一个几何体的位置npos同样根据f为角度旋转.
再以f为bios插值两个位置的值.

5.以中心位置指向当前位置为方向,为每个点设置向外扩张再收缩(这里使用sin函数,f是0-1, 对应正弦 由0-1-0.)

3.设置拖尾和颜色.

结果如下
7.使用约束的粒子变换
1.关于dop网络中的sopsolver(constrain geometry )
在 Vellum 的 DOP 环境中(或者高级 SOP Solver 接口中),这四个部分分别对应不同的物理数据流。理解它们就像理解一个提线木偶的各个部分。
① Geometry (几何体 / 木偶本体)
- 是什么: 這是实际渲染出来的东西(布料的 Grid,头发的 Curve,沙粒的 Points)。
- 包含关键属性:
P(位置),v(速度),orient(旋转)。mass(质量) /w(质量倒数)。friction(摩擦力),bounce(弹力)。
- 在这里做什么:
- 修改
mass来让某些部分变重。 - 修改
v来制作瞬间的推力(比如爆炸)。 - 修改
Cd来做可视化。
- 修改
② Constraints (约束 / 提线与关节)
- 是什么: 这是一堆只有线(PolyLines)的几何体。每根线连接 Geometry 中的两个点(或者一个点和空间坐标)。
- 包含关键属性:
restlength(原长):线原本有多长。stiffness(刚度):拉长这根线有多难。damping(阻尼):晃动停止得有多快。breaking(断裂):是否允许断开。
- 在这里做什么:
- 这是此节点最常用的地方。比如:
if (force > threshold) removeprim(0, @primnum, 1);(如果拉力太大,就删掉这根线/撕裂布料)。 - 动态变软:随着时间推移,降低
stiffness模拟冰激凌融化。
- 这是此节点最常用的地方。比如:
③ Impacts (撞击 / 痛感神经)
- 是什么: 这是一个临时生成的点云。只有当物体发生碰撞(Collision)时,这一帧才会产生数据。
- 包含关键属性:
P:碰撞发生的具体位置。force:撞击力度有多大。normal:撞击的方向。otherobjid:撞了谁。
- 在这里做什么:
- 这是触发器。例如:如果检测到
Impacts里有数据且force很大,就触发声音,或者把 Geometry 里的对应区域颜色变红(受伤效果)。
- 这是触发器。例如:如果检测到
④ Feedbacks (反馈 / 内部应力)
- 是什么: 这是一个比较高级且容易被忽视的数据流。它记录了约束为了维持现状而施加的力。
- 通俗理解: 如果你用力拉一根橡皮筋,橡皮筋也在用力拉你的手。Feedbacks 记录的就是“橡皮筋拉手的力”。
- 用途:
- 通常用于基于应力的断裂(Stress-based Breaking)。
- 虽然我们常在 Constraints 上判断断裂,但有时候需要知道“累积的应力”或解算器内部的反馈力,这时会用到这个数据流。
- 注意: 在简单的 Vellum 流程中,这个端口经常是空的,除非你在 Solver 设置里专门开启了 Force Feedback 相关的输出选项。
编译块的作用.是加快结算速度.
2.基础设置
1.scatter points
设置属性"cluster",设置分组,设置边界信息(以便于在dop solver中从上到下依此映射"mass"使其从上到下依次"解冻",mass=0则静止(表示质量无限大)).
设置rest也是为了方便映射mass

3.使用[ vellum configure grain ]节点将点配置为可以在vellum中求解的颗粒(就是设置一些属性).
增加了 isgrain, mass, pscale, v,属性
在进行下一步之前将"target"组的"mass"设置为0.让目标点保持不动.
4.使用[ vellumconstraints ]节点设置glue约束.
在这里手动设置由起点到目标点的约束,设置连线,设置分组.使用[attribute transform]将其他的prim(约束属性)转移到新的约束上
约束(prim)上的属性: compressstiffness(压缩刚度),constraint_tag, dampingratio,restlength, restlengthorig, stiffness, type.

5.vellum solver
1.设置popwind
2.设置[ sopsolver(constraints geometry) ]
先设置其从上到下依次"解冻"的效果.

3.设置与目标点的约束逐渐增大,以将点拉向目标位置.
1.这里使用[ expandpointgroup ]函数,获取geometry中的"target"点组中的点编号.以得到其点上的bound属性.
这里再prim中使用@ptnum获取的是对应prims的第一个点(由于rest存在于每一个点,所以这里也可以得到rest属性值).
y值由上到下,映射为1-0,再乘以frame,得到150-0帧.
f值为0-1,上面的点从0 到 $FEND-offset(0-250) 帧从 150/400 到 1.下面的点则从(0-400)帧对应0-1.

4.设置原本的约束"stretch"从保存的"reststiffness"逐渐减小为0.
6.补充知识
1.stiffness指的是约束的强度,将粒子拉回初始静态状态的强度。
八.拼图
1.基本形状
1.依据line 的curveu信息,将其映射为0-1的sin值(塑造拱形)作为高度(这里是z轴作为高),

2.再依据高度映射x(左右)位置,使其圆弧可以向内凹。

想要控制下面的点向中间收缩,先将z轴(即高度)从低到高映射为1-0(越下面的点z值越大),此时如果直接相乘(需要先回中点)越高的点(z值越大)x轴坐标收缩越多越靠中
“xs”:映射高度 所以底部为1,顶部为0.(从1--0--1)
再将其乘以sin(ang),这里乘以sin正弦函数,是为了==提取中间部分==
sin(ang):两端为0,中间(顶端)为1(从0--1--0)

两者相乘使其底部端点为0, 顶部为0,保留中间高度的点插值。

由于这里用乘以x轴坐标来设置位置,所以需要反向,1-xs,使得底步和顶点的值为1,在放缩中保持不变,中间的点被放缩。位于领口处放缩最大。

3.使用[ convertline ]将原始图形转换为line

1.使用 [ resample ]将每个线段设置为和基础图形一样的段数
2.依据基础图形的x和z值,在作为原始图形每个prims的每个点沿切线和up方向的值.

这里的"up"由法线"N"和切线"tan"叉乘得到
新的坐标由起点(每个prims的第一个点)坐标加上沿切线和up方向分量,乘以restlength(每个prim原本的长度,应为这里基础图形长度为1.)
4.设置随机凹槽位置,使用[ sort ]随机排序prims,在使用reverse反转一部分顺序.
注意这里的[ reverse ]设置,首先==这里的"-"不是减号==,==是0到多少==,先执行反引号中的代码,这里的[ opinput() ]函数返回连接到给定输入的节点的名字(这里返回连接到 当前节点(".")的第0个输入的节点的名称,也就是上一个[sort]节点),[ rint() ]函数,四舍五入.

可以使用[ opinputpath() ]函数,直接获取连接节点的绝对路径.

5.使用solver解算器模拟吹散"拼图".
"cen"和"id"属性跟随原始每个"拼图"的,经理过[remesh]之后,原始每个"拼图"属性任然保留.(即使prims数量增多)

这里是依据每个"拼图" 的prims的两个属性不变(中心点位置和id).
2.使用[ pointprims() ]获取每个点的prims的第一个prims编号.
以此获取每个点对应prim的属性(中心点位置,id).
3.依据当前中心点位置"cur_cen"和"id"设置随机的方向,注意这里保留了y轴0-1的范围.使其向上,只在xz方向有正负的随机值.
4.依据不变的原始中心位置"ori_cen"(输入1,始终不变),设置y值为从上到下映射为0-1.开始的t值由当前帧到一半的时间轴映射为0-1,即一半的时间就从上到下全部逐渐扩散条件.
5.设置随机旋转轴(使用[ rand() ]函数,同样依据属性"id".)设置随机旋转角度,依据"vel"速度属性的长度,从0到最大速度映射到0-角度.
6.更新位置的旋转,更新速度属性.更新位置,设置中心位置属性.

6.设置颜色(依据挤出时的分组)

7.结果
九.wiggle pattern with vellum 使用vellum的摆动
1. 为Circe设置hair constraint, 保存原始restlength


2.在solver内设置restlength随时间增长.
3.在将circle使用[ ray ]节点投影到grid上,注意这里要==设置pprevious属性==
1.关于==@pprevious==属性,代表上一个子步结束的位置.(用以计算速度个惯性)
2.关于solver中的==FORCE==和==SOURCE==(output)
十.磁场线模拟
1.设置磁极.

2.计算velocity

版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
彬的特效学习指南!
喜欢就支持一下吧