Unity中簡單的優化物理系統


這個篇文章的主要目標是給予你一個關於在Unity中簡單的優化物理系統


我的遊戲物理系統有什麼錯誤嗎?


怎麼去處理遊戲物理系統?


Unity 物理系統有什麼缺陷嗎?


Unity 是怎樣處理物理系統的?


我在 Unity 物理系統上做了什麼控制?


在我開始使用遊戲物理系統之前我應該關心什麼事情?


我應該在時候避免使用物理系統?


我看到了幀速率在下降,這是否是物理系統導致的?


當涉及到物理系統時,便會有以上這些問題,或許你會有更多像上面類似的問題。


是的,是的,我知道!我們全怪那個平果,它爲什麼要在那一天降臨到牛頓的頭上?爲什麼呢,上帝?


物理學也許不是每個人最愛的科目,但是物理學在遊戲開發行業中真的是一個非常重要的角色。


想象一種情況,在緊要關頭你最終決定提出做一個大事情。一個讓人矚目的,一個使用逼真的物理和圖像的大遊戲。


設計已經創建出來,架構已經完成,一切看上去似乎已經準備就緒。但是你最終坐了下來,開始在最棘手的部分上工作,“物理系統”!!


此時,似乎所以東西都崩潰了;你無意中看到了很低的FPS,奇怪的移動,碰撞器/觸發器 出現了問題,高CPU使用率等等。


不恰當或者不正確的使用物理系統可能會把一些遊戲玩家嚇跑。這不只是關於不恰當的使用物理系統的問題了;這是關於一個遊戲可玩性高不高的問題了。


這些都是不容易解決的問題。物理系統是遊戲開發過程中最困難,也是最重要的一部份,這是無法避免的!!


人們可能會說:“好的物理系統需要一個超快的CPU!”。


但是,請相信我,這句話不一定都是對的。多數情況下,可以通過由淺入深進入Unity的海洋中學習Unity 的物理系統是怎樣工作的,以便我們實現更好的物理系統。


在我還是一個程序小鮮肉的時候,我便要處理100多個與物理相關的事情。這讓我花了近一年的時間記錄下了處理物理相關的關鍵點。


因此,我決定寫這篇文章。幫助大家跳躍這個學習階段的痛苦,成爲一個專業的物理系統開發者。


我不打算講關於物理系統在Unity中是如何工作的,然而我將會在怎麼優化你的物理系統中列出技巧和要點。所以,如果你是一個新手,我建議你先去大概瞭解一下Unity 物理系統。


物理學是一個非常非常龐大的、廣泛的概念,我決定分成不同的部分,儘可能做到簡單。


接下來,這是一個漫長有趣的過程,請你趕緊繫好你的安全帶,讓我們開始吧!


降低固定時間步(Fixed Timestep)

在Unity文檔的說明如下:


“一個不受幀速率影響的時間間隔,用於指定在 FixedUpdate() 函數中執行物理計算每一幀的時間間隔


默認值爲 0.02(每秒),這顯示了每 20ms(毫秒)物理更新將會被執行一次。所有 FixedUpdate() 也會每20ms調用一次。


你需要不停的改變這個值,以獲得理想的效果。


例如:


“如果你打算做一個簡單的卡牌遊戲,這不需要使用太多的物理系統。然而最好減少調用物理引擎的次數。但是這操作要很細心一點;如果你減少過多的物理引擎調用的次數,你也許不會得到你想要的物理效果。”


讓我們通過下面的案例更好的理解 Fixed Timestep 吧!


步驟 1) 創建 3-4 個 球體。讓他們保持一些距離:




步驟 2)創建物理材質(通過在Assest文件夾中按下右鍵->Create->Phycics Material),並且設置摩擦係數(Friction Amount)的數值爲 0 ,然後設置彈力系數(Bounciness)爲 1,再設置彈力混合(Bounce combine)爲最大值:




步驟 3)將該物理材質添加到球體碰撞器的物理材質卡槽中去:




步驟 4)爲球體添加剛體組件(這將意味着此物體時物理對象):




步驟 5)創建一個平面,並且爲其創建一個物理材質(先使用默認值),添加到平面上:




步驟 6)讓創建的球體位於平面的上方,並且設置球體的重力選項盒爲勾選狀態。




步驟 7)點擊 Play 按鈕,並且查看一下結果。


這個球在做一下一上的動作。(不好意思,污了一下下。)


那麼,這與固定時間步(Fixed Time Step)有什麼關係呢?


上面只是一個簡單的設置,現在我讓我們開始玩耍 Fixed Time Step 的值吧!


找到 Edit>>Project Settings >> Time,在那裏,你能找到 Fixed Time Step ,它的默認值爲 0.02 (正如我之前提到的那樣)。




現在讓我們設置它爲 0.1,然後按下 Play 按鈕開始遊戲。


你有發現有什麼不同嗎?


首先你會注意到,這些球的運動非常的慢。


然後,你會看到球體穿過了平面而不是反彈回來。


你會問爲什麼?(不需要彈跳如此的快呀!啊哈哈)


好的,如果你設置 Fixed Time Step 爲 0.1,這就意味着物理更新將在每100ms(毫秒)執行一次,這很快就會注意到,將無法檢測到碰撞。


這表明,過多的降低 Fixed Time Step 的也是不恰當的。現在讓我們改變 Fixed Time Step

的值爲一個更爲實際可行的值 0.03 - 0.04。(具體根據球體的需要來定)


現在,如果你開始遊戲,你不會看到任何改變。只要看上去還行,那就OK。如果你細心的檢查一番,物理碰撞檢測會有一點點不同的。


看看下面的圖片:




提示

如果你不能跟上步驟來,那麼請你參考一下Unity的官方文檔。適當的理解 Unity 物理引擎是必須的。

物理碰撞檢測會有點延遲,只會在當前幀結束之後才反彈回去。


這在你遊戲處於正常FPS下可能觀察不到,但是這可能會影響到物理效果。但只要你的需要滿足了,這也是沒什麼關係的。


這將有什麼幫助呢?


任何時候你從物理計算中節省下來的計算資源,都可以讓給渲染和其他計算密集的處理,所以就可以讓你的遊戲更加出衆。


通過設置 Maximum Allowed Timestep 在物理系統中保持檢查!


在Unity文檔中的定義如下:


“一個不受幀速率影響的時間間隔,當幀率爲最低峯值的時候,物理計算和 FixedUpdate() 事件將不會被執行”


那麼,這意味着什麼呢?


讓我們先在正常的遊戲下,去理解它(Maximum Allowed Timestep)。


如果你的遊戲在運行的時候能保持在 60 FPS,這就意味着每一幀會執行 0.01666秒。意味着每一幀需要花費 16.7ms(毫秒)。


現在,讓我們把 Fixed TimeStep 設置爲 0.01,這表明物理更新將每 10ms 執行一次。


這表明,在每一幀中至少會調用一次物理更新,因爲 10ms<16.7ms. 現在讓我們假設由於某種原因幀率降低到了 30 FPS。


那麼,每一幀將會執行 0.0333秒(也就是33.3ms) 。也就意味着在每一幀中會調用3次物理更新(因爲一次物理更新花費10ms)。這意味着如果幀率繼續下降,每幀內的物理調用還會更多。


這將會導致程序崩潰。爲了解決這個問題,下面引入 Maximum Allowed TimeStep。


它的默認值爲 33ms(可能是作者搞錯了,明明就是0.33333秒 = 333。33ms啊)。正如 Maximum Allowed TimeStep 定義:每當物理更新超過指定的時間,物理更新將會停止。因此,這便爲其他進程節約了資源。


在我們的案例中,如果每一幀執行時間增加到 40ms,這將會調用更多的物理更新。


但是現在我們設置 Maximum Allowed TimeStep 爲 0.033,也就是33ms ,物理更新將會在 33ms 後停止調用,也就是執行3次物理更新後,便會停止調用,儘管每幀的執行時間超過 50ms 也會如此。


因此爲其他沉重的進程節省下一些資源。


這聽起來非常的棒,不是嗎?


但還是有會一些限制的負面影響。每當發生性能故障,動畫和物理便會放慢(意味着畫面卡頓,延遲)。


因此,要牢記Maximum Allowed TimeStep 同樣是一個重要的因素,如果使用得當,將會得到非常好的效果。


總是有 1-1-1 的比例


放大一個沒有物理的對象是沒有問題的(就是沒有與物理相關組件的物體對象),但是當一個物體時一個物理對象時,我建議你不要對該物體進行縮放。縮放會導致奇怪的碰撞檢測,也會影響到物體的下落方式。


例如:


“一塊大石頭在沒有任何空氣阻力的情況下會很快的落到地面上(如從塔上或其他地方掉下來)。但是如果它周圍的物體都放大了,那會讓下落看起來速度很慢”。



還有一個選項是調整重力加速度的值讓他看起來變得正常,但是這不是最正確的做法。正確的做法應該是保持使用1-1-1的縮放比例,因爲Unity的物理引擎在這種情況下工作的最佳。


給你的對象設置恰當的質量


和縮放一樣,質量也需要保持精確。


讓一架飛機的質量爲 1kg 正確嗎?


如果你考慮到度量系統準則,Unity的 1 個單位等於 1 kg 質量。同樣的,Unity的 物理系統是無量綱的。但是,如果你假定 Unity 的一個單位的長度爲米,那麼,一個質量的單位爲 kg。


你可以得到更完美的結果。並且,Unity在努力解決高浮點數問題,所以儘量削減取值範圍是比較理想的解決方案。


這意味着,如果假設你的飛機重 1kg ,那麼你的輪子必然不會超過 1/1000 kg。


儘可能避免使用網格碰撞器(Mesh Collider)


對任何物理引擎來說,基於網格的碰撞檢測都比原始的碰撞檢測需要更多的計算量,這是一個事實。Unity在內部使用了 Nvidia 的 PhysX,因此這是沒有什麼不同的。


一般來說,


“對於不同碰撞檢測的相對成本從高到低的排序爲:三角形網格、凸包(具體可以百度百科)、膠囊體、球體、盒子(六面體)、平面、點”


通常,網格碰撞器(Mesh Collider)被標記爲凸包(也建議大家這麼標記),它將被限制到255個三角形。只有在兩個網格碰撞器被標記爲凸面(Covex)時才能相互發生碰撞檢測。




在 Unity 文檔中的說明:


”使用網格碰撞器時會有一些限制。沒有標記爲凸面(Convex)的網格碰撞器只支持在一個沒有剛體組件的遊戲對象(GameObjecet)上發生碰撞,如果你想要在一個剛體上使用一個網格碰撞器,這必須要標記爲凸面“


理想情況下,應該儘量避免使用網格碰撞體,因爲他們會比傳統的碰撞器(球體,立方體,膠囊體)帶來更多的計算負載,所以最好還是少用。


替代方案是什麼呢?




一個簡單的替代方法就是讓對象的子物體使用原始(傳統)碰撞器把它們組合起來(如上圖所示)。這樣會減少一定的計算量,因爲原始(傳統的)碰撞器計算速度比較快。


對於複雜的網格,你通常可以使用 Blender(小巧的建模軟件)或者其他工具來將它們分解成一些小部分。然後可以用傳統碰撞器直接替換掉這些小部分的網格。


我希望我已經給你一個確切的優化描述,但是不幸的是,每個網格都是不一樣的,對於我給出一個確切的描述是非常困難的。


後續很快就會來到


這個列表會很長,而且看上去會沒有盡頭,所以讓我們先休息一下,後續的博客會繼續介紹其他的提示。


同時我也不希望你一下看太多關於物理的東西而產生不適。


請繼續保持關注,然後先從上面幾個點開始優化。如果你有更好的替代方案,請也和我們分享一下。如果對上面討論的內容有任何問題,或者有任何疑問,請在評論區留言,我會很高興能提供任何幫助。


總結:該篇文章大體講了一下幾個關鍵字:Fixed TimeStep、Maximum Allowed TimeStep、Mesh Collider、Convex。


這些東西都能在官網組件手冊中找到一些詳細的說明,如果看不懂該文章所說的內容,還請大家自行去看一看官網的組件手冊(還記得我給你說的 Unity 聖典嗎)



轉載自公衆號:Unity牆外的世界

發佈了45 篇原創文章 · 獲贊 387 · 訪問量 84萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章