Cocos Creator 3.0 3D 物理講解
為更好地幫助大家絲滑升級,減少開發(fā)阻礙,我們帶來了「Cocos Creator 3.0 技術(shù)專欄」第三期,為大家詳細講解 Cocos Creator 3.0 3D 物理。
在此也統(tǒng)一回復(fù)下大家比較關(guān)心的問題:
本專欄將不定期保持更新,包括 2.X 升級攻略等,盡力幫大家降低升級成本。
關(guān)于文檔的問題我們一直在持續(xù)更新中,有任何問題也可以隨時反饋給我們。
今天我們將通過一些概念和案例,來為大家介紹如何使用 Creator 的 3D 物理框架,以便未進行過物理開發(fā)或者不熟悉該框架的開發(fā)者們可以輕松上手。
Creator 的 3D 物理是一套全新的開發(fā)框架,它的目標是使物理開發(fā)在兼具性能的同時變得更加簡單。
以下內(nèi)容主要講解其中使用到的功能和技術(shù)原理,篇幅有限無法涉及到所有的細枝末節(jié),但大部分內(nèi)容在引擎文檔均有介紹,可以配合閱讀。
01
選擇引擎
在 Creator 中進行 3D 物理類應(yīng)用的開發(fā),第一步就是選擇物理引擎,目前提供了三種選擇,分別為 builtin\cannon.js\bullet(ammo.js),它們之間主要的區(qū)別是包體、性能和功能特性。
| 物理引擎 | 特點 |
|---|---|
| builtin | 極其輕量的碰撞檢測系統(tǒng),僅支持盒、球、膠囊體形狀和觸發(fā)事件 |
| cannon.js | 純 js 開發(fā)的物理引擎,支持大部分特性,易于擴展,但性能不夠好,包體約為 141 KB |
| ammo.js | 由 bullet 物理引擎編譯而來,支持所有特性,性能最優(yōu),但包體較大且不易擴展,其中 js 版本的包體約為 1.32 MB,wasm 版本的包體約為 690 KB |
其中主要的功能特性支持情況如下:
| 功能特性 | builtin | cannon.js | ammo.js |
|---|---|---|---|
| 質(zhì)心 | ? | ? | ? |
| 盒、球 | ? | ? | ? |
| 膠囊 | ? | 可以用基礎(chǔ)形狀拼湊 | ? |
| 凸包 | ? | ||
| 靜態(tài)地形、靜態(tài)平面 | ? | ? | |
| 靜態(tài)網(wǎng)格 | 極其有限的支持 | ? | |
| 圓錐、圓柱 | ?(凸包實現(xiàn)) | ? | |
| 單純形 | 有限的支持 | ? | |
| 復(fù)合形狀 | ? | ? | ? |
| 射線檢測、掩碼過濾 | ? | ? | ? |
| 多步模擬、碰撞矩陣 | ? | ? | ? |
| 觸發(fā)事件 | ? | ? | ? |
| 自動休眠 | ? | ? | |
| 碰撞事件、碰撞數(shù)據(jù) | ? | ? | |
| 物理材質(zhì) | ? | ? | |
| 靜態(tài)、運動學(xué) | ? | ? | ? |
| 動力學(xué) | ? | ? | |
| 點對點、鉸鏈約束(實驗) | ? | ? | |
| wasm | ? |
02
概念講解
以下向大家介紹了物理模塊比較重要的組件和功能。
Static / Kinematic / Dynamic
剛體類型 Static 靜態(tài)剛體,可用于描述靜止的建筑物,只與 Dynamic 和 Kinematic 類型的物體產(chǎn)生事件 Dynamic 動力學(xué)剛體,能夠受到力的作用,物理引擎會接管該物體的運動,通過物理層的數(shù)值來操控 Kinematic 運動學(xué)剛體,通常用于表達電梯這類平臺運動的物體,通過修改變換信息來操控 下圖中白色為靜態(tài),藍色為運動學(xué),黃色為動力學(xué)。其中白色和藍色都是操控的變換信息,很明顯的看出幾個表現(xiàn)
白色和藍色之間會出現(xiàn)穿透現(xiàn)象 白色的靜態(tài)物體也可以運動 兩個黃色方塊表現(xiàn)不同,白色上方的靜止不動,藍色上方的會跟隨著運動

以上現(xiàn)象的原因是:
靜態(tài)和運動學(xué)都不會受到力的作用,所以產(chǎn)生了穿透,這是正常現(xiàn)象 靜態(tài)物體的確是可以運動的,靜態(tài)是指在時空中,每一個時刻都是靜態(tài),不會考慮其它時刻的狀態(tài) 與靜態(tài)物體不同,運動學(xué)物體會根據(jù)附近時刻估算出運動狀態(tài)(比如速度),又由于摩擦力的作用,因此帶動了黃色方塊 RigidBody / Collider / Trigger
組件類型 剛體組件(RigidBody) 它負責(zé)操控物理對象與運動相關(guān)的屬性,以及配置分組,一個節(jié)點最多一個 碰撞器組件(Collider) 它負責(zé)操控物理對象上形狀相關(guān)的屬性,一個節(jié)點可以有多個 觸發(fā)器(Trigger) 它是勾選上了 IsTrigger的碰撞器組件,它會像幽靈一樣穿透其它物體,并提供穿透開始、保持,以及結(jié)束的事件是否一定要加剛體組件是提問最多的,這里介紹一個小技巧:
需要配置分組,加 需要設(shè)置為運動學(xué)或者動力學(xué)類型(不加意味著是靜態(tài)類型),加 Raycast / Mask Filter / Collision Matrix
功能模塊 射線檢測(Raycast) 利用射線與其它碰撞體進行碰撞檢測,并記錄相應(yīng)的碰撞數(shù)據(jù) 掩碼過濾(Mask Filter) 利用位運算實現(xiàn)兩個物體間是否相互過濾,重要的碰撞檢測優(yōu)化技術(shù) 碰撞矩陣(Collision Matrix) 它用于初始化物體的分組和掩碼,是掩碼過濾的上層封裝
這套框架還有很多需要打磨的地方,例如有些開發(fā)者認為在靜態(tài)對象上配置分組不夠便捷、分組不應(yīng)該和節(jié)點的層剝離開、射線不應(yīng)該有組。
這些我們都記錄下來了,同時也在尋找更友好的方式。在這里感謝開發(fā)者們寶貴的反饋建議。
03
使用講解
以下將會結(jié)合一個射箭范例中的幾個問題場景,介紹對應(yīng)使用到的功能特性和解題思路,以及涉及到的易誤點。
用基礎(chǔ)形狀組合十字架——復(fù)合形狀
下圖中用兩個盒形狀組合一個十字架,節(jié)點上所有的碰撞體組合成了一個十字形狀,這是實現(xiàn)帶有凹面形狀最基礎(chǔ)的方法:

容易誤用的地方是在多個節(jié)點中添加碰撞體拼湊出十字架后,希望它碰撞后可以保持整體結(jié)構(gòu)進行運動,這在目前的結(jié)構(gòu)中是無法做到的,只能往單個節(jié)點上添加碰撞體來實現(xiàn)。
射箭與回收箭——運動學(xué)、動力學(xué)、事件
射箭的第一步是拉弓,箭需要完全跟隨彈性繩骨骼一起運動,不希望箭受到物理規(guī)則的影響,此時應(yīng)將箭的剛體設(shè)置為 Kinematic 類型;第二步是松開彈性繩發(fā)射箭,這時希望給箭設(shè)置初速度后,可以按照物理規(guī)則進行運動,因此將箭的剛體設(shè)置為 Dynamic 類型

回收箭的大致過程是在箭射出去后,一旦觸碰到觸發(fā)區(qū)域就將其還原到弓上。這可以通過制作監(jiān)聽區(qū)域來實現(xiàn),首先利用碰撞體組件拼湊出區(qū)域,同時將碰撞體組件的 IsTrigger 勾選上。(下圖中的藍色地板為監(jiān)聽區(qū)域)

易誤點:
利用修改變換信息來操作動力學(xué)( Dynamic)類型的剛體,應(yīng)當通過速度、力或沖量等物理層的數(shù)值利用靜態(tài)( Static)類型的剛體來監(jiān)聽事件,靜態(tài)剛體只會和帶有類型為運動學(xué)或動力學(xué)的剛體產(chǎn)生事件,可以更改為運動學(xué)(Kinematic)類型,或者事件通過另一方進行注冊監(jiān)聽事件時僅監(jiān)聽了觸發(fā)開始( OnTriggerEnter),但是誤以為包括了觸發(fā)保持(OnTriggerStay)和結(jié)束(OnTriggerExit)
瞄準——碰撞矩陣(過濾檢測)、射線檢測、靜態(tài)平面
瞄準是射箭前的步驟,準心處于箭頭指向所在的射線上,在十字架前面加一個靜態(tài)平面碰撞體,然后利用射線檢測就可以得到準心的位置;

靜態(tài)平面只是用來做射線檢測,給它專門建立一個分組,并且不與箭、蘋果等等物體進行檢測,這是最通用的性能優(yōu)化方法

調(diào)用射線檢測方法時,設(shè)置傳入掩碼為僅和靜態(tài)平面檢測,即 0b10(二進制表示法)。

易誤點:
分不清剛體組件上的分組和節(jié)點上的層。這兩者的概念類似,但是使用者不同,分組的使用者是物理模塊,層的使用者是渲染模塊 對掩碼的理解不到位,不知傳何值。這里提供一個小技巧,以一個能夠篩選出 Others的掩碼舉例,首先Others的index值為2,哪么只要讓二進制掩碼從右往左的順序第2位為1,就能讓Others通過篩選,也就是ob100(這里強烈建議不要隨便更改分組的索引)誤認為射線檢測接口的返回值是擊中的數(shù)據(jù)。獲取結(jié)果有專門的接口,此處設(shè)計是為了強調(diào)這是個復(fù)用對象。為了減少垃圾內(nèi)存,每次調(diào)用接口只會更新它們的數(shù)據(jù),而不是重新生成新的(若需要持久記錄,哪么可以克隆一份)
射擊蘋果——靜態(tài)網(wǎng)格、凸包、多步模擬(步長調(diào)整)
一般的蘋果都帶有凹面,處理好凹類或帶連續(xù)平滑不規(guī)則曲面的模型都非常棘手,這是因為目前成熟的理論和技術(shù)都建立在離散、凸包的世界之上(微積分中用差分近似表示微分就是最典型的范例)。
在實時物理引擎中,對于這類物體只能支持到靜態(tài)或運動學(xué)類型的剛體層級,對于動力學(xué)就束手無策了。然而不幸的是,真實的蘋果運動表現(xiàn)強烈依賴動力學(xué),這種情況只能給蘋果填加凸包形式的網(wǎng)格碰撞體(需將 convex 勾選上),再加上一個動力學(xué)剛體,用近似物體去參與模擬

運動表現(xiàn)與模擬參數(shù)有非常大的關(guān)系,穿透是最具有代表性的現(xiàn)象,這可以通過縮減步長和增加步數(shù)來實現(xiàn),調(diào)整步長有個小技巧:輸入分式,即 1/Frame,其中 Frame 表示幀率

易誤點:
在帶有未勾選
convex的網(wǎng)格碰撞器上添加了的動力學(xué)剛體,與其它物體產(chǎn)生了穿透現(xiàn)象,或者說完全沒有反應(yīng),這是典型的錯誤使用,只有勾上convex的才能支持動力學(xué)剛體對一個頂點數(shù)極多的模型開啟了
convex,過多的頂點數(shù)會使凸包的面數(shù)增多,這對性能有很大的影響,而且實際上并不需要面數(shù)特別多的凸包,一般建議模型的頂點數(shù)應(yīng)小于255開啟凸包后,模型的凹面處的接觸不貼近,這是正常現(xiàn)象,現(xiàn)在的實時技術(shù)是將模型用多個凸包組合來解決,如下圖所示

4. 只調(diào)整了步長,但未調(diào)整步數(shù),這兩者需要相互配合才有效果。小技巧是,步數(shù)可以隨意設(shè)置較大的值,步長根據(jù)最大的速度值進行調(diào)整,值越大,步長應(yīng)當越小
04
運動控制
以下將介紹如何利用碰撞數(shù)據(jù)實現(xiàn)一個動力學(xué)類型剛體的運動控制。
碰撞數(shù)據(jù)
如下圖所示,紅色的球表示的是碰撞點的位置,藍色箭頭指的是碰撞點所處面的法線。碰撞數(shù)據(jù)需要通過碰撞事件來獲取(事件提供的碰撞數(shù)據(jù)是復(fù)用對象)。

地面判斷
角色是否在地面上,可以通過法線的指向來得知,對應(yīng)的條件為normal.y > 0。有時候還需要知道地面的傾斜情況,這里通過normal.y的大小就能知道,越接近于1,哪么地面就越平(法線垂直向上);越接近于0,哪么地面就越陡峭。

跳躍
一旦能夠確定是否在地面后,就可以加上跳躍行為了。首先需要明確的一點是,這里使用的是動力學(xué)類型的剛體(原因是我希望通過物理引擎接管剛體后得到更加真實的物理反饋),所以需要通過改變物理數(shù)值來達到目的,例如直接將角色線性速度的y分量設(shè)置為5,如下圖(圖中碰撞體用的是膠囊體,這與實際場景相關(guān),可自行更改)。

直接改y軸速度,可以良好的工作在完全水平的地面上。但有時候跳躍還需要根據(jù)地面斜度來做出不同的行為,這里提供一個思路:提供一個配置因子,范圍為0到1,根據(jù)因子將當前法線和垂直法線插值,得出目標法線,再乘以跳躍的速率,進而得出期望的跳躍速度,將其加入到角色的線性速度之中。
行走和站立
站立行為,如果希望角色不會摔倒,哪么直接將AngularFactor全設(shè)置為0即可。行走行為,可根據(jù)角色的運動狀態(tài)來實現(xiàn),假設(shè)需要將角色往x軸運動,哪么就修改角色x軸的線性速度。因此控制行走,只需要兩個量,一個是運動方向,另一個是運動速率。


做出好的運動控制的唯一竅門就是控制好速度,但這也是最容易錯誤使用的點:
隨意設(shè)置速度,這是運動不真實最根本的原因 設(shè)置過大的速度,這將很容易出現(xiàn)穿透現(xiàn)象,可以嘗試上文介紹的多步模擬技術(shù)
沒有掌握控制速度的方式,有些開發(fā)者直接修改為某個固定值大小,這當然不是錯誤的做法,但修改速度之前應(yīng)當考慮清楚這是不是想要的結(jié)果。
有個小技巧是,如果是跳躍行為,可以考慮直接設(shè)置為固定值;
如果是行走行為,更好的方式是根據(jù)上個時刻的狀態(tài)進行修改
使用了
Kinematic類型的剛體,期望物理引擎會幫助你處理好碰撞行為,通過上文可以知道這是不可能的。但實際上有很多好的角色控制都基于
Kinematic進行實現(xiàn),這里面的技術(shù)細節(jié)遠比本文介紹的復(fù)雜。
05
結(jié)語
以上大部分的內(nèi)容案例均可在案例倉庫中找到,比如上面的截圖中用來輔助顯示碰撞點信息的組件,其他內(nèi)容比如弓箭、運動控制的案例也會持續(xù)合并進去,請感興趣的同學(xué)持續(xù)關(guān)注。
相信大家看到上面糖豆人類的物理實現(xiàn)展示也很激動,3.0 引擎目前已經(jīng)完全可以支撐同類型游戲的開發(fā),大家可以按照這篇文章中的指引和參考我們的范例多多嘗試。
未來在物理引擎上還有很廣闊的探索空間,目前在計劃中的包括:
原生平臺 PhysX 物理引擎接入,將大大加強原生平臺的物理性能 更多物理約束類型支持 布娃娃系統(tǒng) 物理驅(qū)動的動畫系統(tǒng) 持續(xù)碰撞檢測(CCD) 節(jié)點鏈組合
后續(xù)本專欄將不定期更新,為大家?guī)戆ǖ幌抻谝韵聝?nèi)容:
《Cocos Creator 3.0 里如何玩轉(zhuǎn) npm 海量資源》by 放空
《Cocos Creator 3.0 的資源系統(tǒng)》by Santy Wang
......
留言告訴我們其他你想看的內(nèi)容,我們也會持續(xù)加強物理引擎的能力,幫助開發(fā)者做出超好玩的物理反饋游戲。
最后,歡迎對物理引擎開發(fā)有興趣的同學(xué)將簡歷甩進我們 HR 的郵箱中!
郵箱地址:[email protected]。
往期精彩



