Niagara链条及蒙皮
- 作者:admin
- /
- 时间:3天前
- /
- 浏览:137 次
- /
- 分类:厚积薄发
【USparkle专栏】如果你深怀绝技,爱“搞点研究”,乐于分享也博采众长,我们期待你的加入,让智慧的火花碰撞交织,让知识的传递生生不息!
(本文使用UE 4.27的版本)
早先看到下面用Niagara实现链条的教程:
Unreal Niagara - Tentacle effect with physics simulation (FULL TUTORIAL)
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/1.png)
后来又看到个进一步的,在此基础上加了蒙皮:
Rigging With Niagara - Part 1: Dangling Cable - Direct Interpolation
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/2.png)
自己照着做了一遍,发现这方法有很多问题,于是又想了个改进方案。
一、Niagara链条
首先根据教程(Unreal Niagara - Tentacle effect with physics simulation (FULL TUTORIAL))实现基础的链条效果,其中几个要点:
1.物理迭代是用Position Based方法,就是对于链条上每个点,计算其相对于各邻接点的平衡位置偏离了多少,偏离多少就移回多少,如果有多个邻接点,则将分别计算的移回向量相加取平均,作为最终移回量,公式如下:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/3.png)
2.在这个链条模拟中,我们把起始粒子的前驱认为是自身,即存在linkPos=pos的情况,所以上式分母中+0.0001就十分必要,否则会因除以零而产生NAN。
3.物理迭代通过添加Simulation Stage实现(只有在GPU Sim下才能用),Simulation Stage中可以设置迭代次数,不同的约束可能需要的迭代次数不同,可以分成多个Stage去做,每个Stage单独设置迭代次数。对于上述长度约束,我试了下需要4次才能效果较好。
4.Calculate Accurate Velocity这一步,若非教程里说了,自己可能想不到。另外Calculate Accurate Velocity可以从迭代次数为4的模拟Stage里移出来,放到后面迭代次数为1的Stage里。
至此,如果是要做锁链之类的效果,只需把粒子替换成圆环模型,就可以了。但我们的目的是想做蒙皮。
二、链条蒙皮
教程(Rigging With Niagara - Part 1: Dangling Cable - Direct Interpolation)讲得比较笼统,但从中还是能大致了解其思路。要点如下:
1.把模拟出的链条上各粒子坐标写到一个ParticleCount x 1像素的RT上,传给材质。并借助RT的双线性插值实现平滑。
2.MeshRenderer的SourceMode要由Particles改为Emitter,这样就不会为每个粒子挂一个Mesh,而是整个Emitter挂一个Mesh:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/4.png)
3.沿着绳子建立切空间,则无论绳子怎么弯曲,蒙皮上各点的切空间坐标不变,利用这点计算蒙皮各点的世界坐标,然后WPO。这一步在材质中进行。
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/5.png)
其中3存在一个问题,就是“沿着绳子建立切空间”,即使在锁定初始点的切空间的情况下,也有无数种结果。
教程中取的是:
T=normalize(p_nxt-p),
B=normalize(cross(T, (1,0,0) )),
N=cross(B,T)。
但这种算法并不能保证当绳子任意弯曲时,相邻质点的切空间足够接近,或者说相邻质点的法线是渐变的。
在剧烈摆动时会出问题,如下视频所示:
于是针对如何对空间曲线生成法线这个问题,搜了一下,下面这个还算吻合:
opengl es - Vector math, finding coördinates on a planar between 2 vectors - Stack Overflow
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/7.png)
主要就是说明给曲线生成渐变的法线,只考虑局部就不行了,需要考虑整体,他给出的代码是其中最简单的一种方法,就是用上一个粒子的法线去算下一个粒子的法线。
我按这个简单实现试了一下,发现效果仍不理想,原因可能有两点:
- 我的分段太稀疏,导致即使考虑了上一个粒子的法线影响,仍然会出现剧烈转折。
- 此算法严格来讲需顺序执行,而Niagara中GPU粒子的执行顺序是乱序的。
于是我暂时放弃了这种基于数学的思路,转而考虑基于物理的思路。
就想是不是可以引入扭矩约束,从而避免相邻粒子朝向差异过大,即避免拧麻花。
三、改进:防止扭转、翻转
我一开始想的是给粒子添加旋转属性,然后想着在模拟阶段修正位置的同时对旋转也作一个修正,但我不知道依据什么更新粒子的旋转属性,于是放弃这个思路。
然后想到,如果升维,把绳子看成有内部结构,如图:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/8.png)
则有可能仅通过对距离作约束就同时起到防止扭转的作用。
绳子截面边数自然是越多越好,摆动起来各方向物理性质更均等,但粒子数也会成倍增加,所以我只试了正三角形截面和正方形截面。出于简单,以下以正三角形截面为例。
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/9.png)
如上图,如果仅像(a)那样连接,侧面是平行四边形,不稳定,可能出现压扁、扭转、翻转三种情况,如图所示:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/10.png)
为侧面添加支架,变成(b),就稳定多了,压扁和扭转都能得到限制,但仍会出现上下翻转问题,如下视频所示:
之所以出现这种情况,是因为以截面为镜面,上下对称的两个点的长度一样,所以从距离约束的角度讲,上下两个位置都是满足条件的解。为了避免这个问题,对隔一层粒子也添加距离约束,如图(c)(d)所示,其中(d)在隔层之间作了全约束,而(c)只作了交叉约束,经试验发现(c)就够用了。
改为(c)后,上下翻转不会发生了,但仍存在自穿插翻转,如下视频所示:
要解决自穿插翻转,通过距离约束貌似是不行了(我没想到),但观察自穿插翻转的特点,容易看出当发生自穿插翻转时,三条侧边一定不再平行。所以想到,如果加一个每段三棱柱三条侧边平行的约束,应该就可以避免自穿插翻转了。具体算法如下:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/13.png)
pos_new=pos_P+safeNormalize(c-c_P)*distance(pos-pos_P)
注:这里只让当前粒子pos所关联的上游边pos_P->pos与上游中轴线c_P->c平行,没有让pos所关联的下游边pos->pos_N与下游中轴线c->c_N平行。因为实际试验发现上下游都处理效果不好,原因可能是当扭转发生时,如果想通过移动当前粒子缓解,让上游平行和让下游平行移动方向必定是冲突的,所以不如只考虑上游。
效果:
可见,无论怎么动,都不会出问题了。
有了鲁棒的三棱柱绳子,就可以算出稳定的法线,这里我们是用第一条棱与相应的截面中心点作差作为法线,然后就可以在材质里构建稳定的切空间,进行蒙皮:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/15.png)
之前是把Position存到了RT里传入材质,现在还要增加一张RT,用来存法线。
蒙皮后效果:
四、正确的蒙皮法线
上面视频中绳子的明暗是不正确的,因为没有考虑绳子弯曲对模型顶点法线的影响。
正确的蒙皮法线计算方法如下:
(1)绳子Tpos切空间基:
T0=(0,0,-1)
N0=(1,0,0)
B0=cross(N0,T0)
(2)vertexNormal在绳子Tpos切空间的坐标:
vertexNormalProjOnT0=dot(vertexNormal,T0)
vertexNormalProjOnN0=dot(vertexNormal,N0)
vertexNormalProjOnB0=dot(vertexNormal,B0)
(3)绳子Bendpos切空间基:
T=采样posRT并差分得到
N=采样normRT得到
B=cross(N,T)
(4)根据蒙皮法线Bend前后切空间坐标不变,计算Bend后的顶点法线vertexNormalBend:
vertexNormalBendProjOnT=vertexNormalProjOnT0
vertexNormalBendProjOnN=vertexNormalProjOnN0
vertexNormalBendProjOnB=vertexNormalProjOnB0
vertexNormalBend=mul(vertexNormalBendProjOnT,T)+mul(vertexNormalBendProjOnN,N)+mul(vertexNormalBendProjOnB,B)
最后还有一个细节问题,就是在没有Bend发生时,Bendpos切空间应该是与Tpos切空间完全重合的。未Bend时T由差分求出来是竖直向下,这和T0=(0,0,-1)吻合,没问题,但未Bend时normRT采样出来的N是否也与N0=(1,0,0)重合,就要看一下了。前面说过,我们是用第一条棱与相应的截面中心点作差作为法线N,那也就是说我们要保证在不Bend时第一条棱与截面中心作差指向X轴,所以截面应如下构建:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/17.png)
修正蒙皮法线后效果:
五、补充
1.Niagara的Custom HLSL中语法注意事项:
(1)错误:int index=index%10;
正确:int index=index %10;//%前要有空格。
(2)错误:NiagaraID idList2={PID,NID};
正确:NiagaraID idList2={ PID,NID };// { 后和 } 前要有空格
报错信息去Output Log窗口看,那里才是详细信息。
2.DebugDraw节点中,不要用drawSphere,其编译时间很长,drawLine和drawBox都编译很快。
3.如果希望不同链条约束强度有差异,或者方便忽略掉一些链条(权重给0),可以用加权版本公式:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/19.png)
4.Slover模块连线过多,一堆GetVectorByID+Custom HLSL节点:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/20.png)
可用如下方法简化:
打开生成的Shader Code:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/21.png)
搜GetVectorByID,可以搜到:
声明处:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/22.png)
使用处:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/23.png)
所以GetVectorByID可以写到Custom HLSL里面:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/24.png)
所以众GetVectorByID+Custom HLSL可合并成一个大的CustomHLSL:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/25.png)
需要注意的一点是,需要保留一个GetVectorByID("Position")节点,以便生成函数声明,否则会报错。
同理,Setup模块也可做同样简化:
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/26.png)
![](http://uwa-ducument-img.oss-cn-beijing.aliyuncs.com/Blog/USparkle_NiagaraChain/27.png)
这是侑虎科技第1763篇文章,感谢作者杨超wantnon供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:793972859)
作者主页:https://www.zhihu.com/people/wantnon
再次感谢杨超wantnon的分享,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:793972859)