博客 / 詳情

返回

UE4彈簧草及擴展

【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)

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.