头图

【USparkle专栏】如果你深怀绝技,爱“搞点研究”,乐于分享也博采众长,我们期待你的加入,让智慧的火花碰撞交织,让知识的传递生生不息!


如果草交互想实现回弹效果,就不能纯靠材质,而要有办法记录历史状态。

找了一圈,发现下面这种在RT上做物理迭代的方案最便捷:【UE5 模拟交互篇】(五)物理场方式实现植被交互

本文复现此法,并做一些简单扩展。

一、弹簧草

基本思路与参考文章相同,只记录一下差异点及注意事项。

1.参考文章中算了多层弹簧,我只算了一层。即将草的尖端看作一层水平弹簧振子。另外参考文章中并没有将弹簧振子锁定在水平平面上,我这里是为了简单而且省通道,直接看作水平弹簧振子。

2.用Offset代替POS。

同参考文章一样,用到posRT和volRT两个RT,前者存位置,后者存速度。但我posRT里存的不是Position,而是Offset,就是此纹素代表的弹簧振子偏离平衡位置的Offset,这样数值范围更小,精度更高,而且方便Debug。

3.Offset和Volecity编码。

我是将Offset分解成offsetDir和offsetLen,然后再将offsetDir乘以0.5+0.5,这样,就全都变成了正值,再写入RT的。从RT采出来则需要进行解码再用。由于我简化为水平弹簧振子,所以offsetDir是二维的,再加上offsetLen,占三个通道。Volecity同理。

当然,如果用RT存负值,就用不着编解码了,也无需将Dir和Len分开存。

关于UE中RT如何存负值,搜到下面帖子(我还没试):

4.在DrawMaterialToRenderTarget材质中通过UV和预设的Box框范围来计算WorldPosition,然后用WorldPosition与传进来的playerPos计算距离,决定哪里下压。

5.分为stampPos、stampVol、updatePos和updateVol四个过程。

  • stampPos是将最新的压草偏移量覆盖到原RT上。
  • stampVol是将覆盖了最新压草偏移量的地方的Volecity清零,避免压草处速度持续积累失控。

6.deltaTime限制最大值,比如deltaTime=min(0.02,deltaTime),这样可以避免卡的时候因deltaTime过大而使速度增量过大。

7.在草的Shader里采样posRT,根据采到的Offset计算Bend。

https://www.youku.com/video/XNjQ1MTkxMDI5Mg==

二、扩展1:弹簧草+Billboard

如果想表达海葵之类的管状生物,且不想用管状模型嫌面数太高,可以用Billboard来实现不管从哪个角度看,都保持恒定的宽度。

在草/海葵材质中,WPO计算如下:

https://www.youku.com/video/XNjQ1MTkxOTQ0NA==

三、扩展2:弹簧香菇

回想上面弹簧草的实现思路,是将平面上每个点看成一个弹簧振子,在RT上去迭代。

那么,如果把模型上每个点看成一个弹簧振子,RT上每个像素对应模型表面一点,对RT进行迭代,岂不是就能实现类似软体的效果了。

这里说“类似”,是因为相比于“正确”的软体实现方法——质点弹簧系统而言,它少了质点之间的相互影响,而只是各质点独立的振荡。这是一个非常大的简化,所以效果上一定会打折扣,但从发散思维角度讲,感觉又是一个不错的联想,所以尝试了一下。

主要问题是如何在DrawMaterialToRenderTarget过程中拿到WorldPosition(因为Blit时材质不是应用在模型上,所以无法在材质中直接拿到模型的WorldPosition)。解决办法是将WorldPosition预烘焙到贴图上,然后在DrawMaterialToRendeTarget的材质中采样此贴图。这个思路跟顽皮狗的车辆战损效果类似:


https://youtu.be/aZJQuHZQakQ?t=2153

只不过,战损效果是把铁皮撞凹陷以后就固定住了,而我们要回弹。

另外前面弹簧草是简化为只在xy平面运动的水平弹簧振子,所以存Offset只需三通道(offsetDir.x,offsetDir.y和offsetLen),Volecity同理。但弹簧香菇表面的振子就不能再看成二维的,而需要是三维的,Offset和Volecity都需要用四通道来存(假设不用RT存负值)。

如何写入RT的a通道,参考:Draw Material To Render Target impossible to control alpha - always fully transparent

即Blit材质Blend Mode选Masked,Shading Model选Unlit,则emissiveColor引脚输出RGB,OpacityMask引脚输出Alpha。另外还需要:勾选Used with Editor Compositing,OpacityMaskClipValue设置为-0.01。

其余就和弹簧草实现一样了。

最终效果如下:
https://www.youku.com/video/XNjQ1MTkxNjMyMA==


这是侑虎科技第1731篇文章,感谢作者杨超wantnon供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:793972859)

作者主页:https://www.zhihu.com/people/wantnon

再次感谢杨超wantnon的分享,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:793972859)


侑虎科技
62 声望21 粉丝

UWA官网:[链接]