布娃娃(Ragdoll)系統(tǒng)
布娃娃系統(tǒng),相信很多玩家已經(jīng)在大部分游戲中遇到過(guò)。作為一個(gè)已經(jīng)成熟并且普及的系統(tǒng),Ragdoll被廣泛應(yīng)用于各種游戲,來(lái)提供一定程度上的物理模擬。

圖中是一個(gè)典型的Ragdoll應(yīng)用場(chǎng)景,敵人在被一拳打飛后,在地面翻滾倒地,整個(gè)過(guò)程顯得非常自然流暢。而且,在整個(gè)過(guò)程中,并沒(méi)有用到任何傳統(tǒng)“動(dòng)畫(huà)”,一切基于物理模擬效果。因而布娃娃系統(tǒng),也是“程序生成動(dòng)畫(huà)”的一個(gè)重要手段。
模型與骨骼
模型
要理解Ragdoll系統(tǒng)為什么能實(shí)現(xiàn)物理模擬動(dòng)畫(huà)的效果,我們首先需要簡(jiǎn)單了解一下,傳統(tǒng)3D游戲中動(dòng)畫(huà)的實(shí)現(xiàn)方式。(已經(jīng)了解的同學(xué)可以直接跳到下一部分)
模型作為我們最常接觸的美術(shù)資源,其本身是由一系列頂點(diǎn)(坐標(biāo))信息組成的數(shù)據(jù)集,因而顯然,單純的模型是純靜態(tài)的,我們?cè)赨nity->Gizoms中勾選Selection Wire就可以看到模型的線框圖。 在Unity中可以看到Mesh Renderer系列組件,其中Mesh就是模型的網(wǎng)格。

那么讓模型動(dòng)起來(lái),要做的就是讓模型的各個(gè)頂點(diǎn),按照一定規(guī)律運(yùn)動(dòng)起來(lái),實(shí)現(xiàn)“動(dòng)畫(huà)”效果,這也是經(jīng)典的“頂點(diǎn)動(dòng)畫(huà)”原理。
但是現(xiàn)代游戲,稍微復(fù)雜的一個(gè)模型常常有幾千上萬(wàn)的頂點(diǎn),讓美術(shù)人員去手動(dòng)設(shè)置每個(gè)頂點(diǎn)的運(yùn)動(dòng)情況顯然不現(xiàn)實(shí),也很難實(shí)現(xiàn)合理的效果。
于是人們想到現(xiàn)實(shí)中,人類靠骨骼帶動(dòng)肌肉運(yùn)動(dòng),我們很少去直接控制身體上某塊肌肉運(yùn)動(dòng),更多是去驅(qū)動(dòng)骨骼。只要骨骼按照一定規(guī)律運(yùn)動(dòng),骨骼附帶的肌肉也會(huì)隨之運(yùn)動(dòng),骨骼動(dòng)畫(huà)的概念應(yīng)運(yùn)而生。
骨骼
“骨骼”其實(shí)是一個(gè)抽象概念,它參考了人體利用骨骼帶動(dòng)肌肉運(yùn)動(dòng)的規(guī)律,為模型創(chuàng)建一個(gè)類似的、抽象的“骨骼”,如圖所示。

圖中就是一個(gè)包含骨骼的模型,這里利用了AnimationRigging插件中的BoneRenderer將骨骼以可視化的形式顯示了出來(lái)(不然骨骼是一個(gè)抽象概念,并不對(duì)應(yīng)某些可見(jiàn)實(shí)體)??梢钥闯?,模型骨骼與人體骨骼非常相似,只是進(jìn)行了一定程度上的簡(jiǎn)化。
那么實(shí)際上, Unity 中的骨骼,只是一系列具有父子層級(jí)關(guān)系的空物體,其層級(jí)結(jié)構(gòu)一定程度上參考現(xiàn)實(shí),父骨骼可以帶動(dòng)子骨骼運(yùn)動(dòng)(例如我們抬起大腿,小腿會(huì)跟隨大腿運(yùn)動(dòng)),Unity的父子結(jié)構(gòu)能夠很好的表達(dá)這一特點(diǎn)。從父骨骼向子骨骼連線,就得到了上圖中可視化的骨骼形狀,更易于表現(xiàn)出骨骼的形態(tài)。

圖中Armature表示的就是層級(jí)結(jié)構(gòu)的骨骼,body則是人物模型,再次說(shuō)明模型與骨骼是分離的。
蒙皮
所謂蒙皮,就是將模型的頂點(diǎn)附加到骨骼上的過(guò)程,也就是決定哪些“肌肉”受到哪些“骨骼”控制。建立好這樣的綁定關(guān)系后,當(dāng)我們驅(qū)動(dòng)手臂“骨骼”時(shí),手臂部分的頂點(diǎn)也會(huì)隨之運(yùn)動(dòng),從而將動(dòng)畫(huà)制作中的控制“頂點(diǎn)”運(yùn)動(dòng)簡(jiǎn)化為了控制“骨骼”運(yùn)動(dòng)。
而頂點(diǎn)的蒙皮信息中,包含了該頂點(diǎn)受到哪些骨骼影響(可以有多個(gè)),及每根骨骼的權(quán)重,這樣在一些復(fù)雜運(yùn)動(dòng)的過(guò)程中,頂點(diǎn)跟隨變化的軌跡會(huì)更加細(xì)膩真實(shí),同時(shí)能消除關(guān)節(jié)連接處的一些撕裂情況。

Unity 中使用 Skinned Mesh Renderer(帶蒙皮的網(wǎng)格渲染器)來(lái)實(shí)現(xiàn)這一效果。
骨骼動(dòng)畫(huà)
在拿到了一個(gè)蒙皮后的人物模型后,我們只需要控制骨骼運(yùn)動(dòng)便可以實(shí)現(xiàn)帶動(dòng)模型頂點(diǎn)運(yùn)動(dòng)。而動(dòng)畫(huà)數(shù)據(jù),實(shí)際上就是記錄了各個(gè)骨骼,在各個(gè)關(guān)鍵幀時(shí)的位置、旋轉(zhuǎn)信息。同時(shí)利用一些算法實(shí)現(xiàn)關(guān)鍵幀間的插值,實(shí)現(xiàn)骨骼的平滑移動(dòng)。(這部分一般交由動(dòng)畫(huà)師在專業(yè)軟件中制作,俗稱K動(dòng)畫(huà),也就是K關(guān)鍵幀)

圖中所示就是一個(gè)動(dòng)畫(huà)文件的信息,可以看到各個(gè)骨骼在每個(gè)關(guān)鍵幀的位置信息。 有了以上準(zhǔn)備工作,我們的模型就可以動(dòng)起來(lái)啦。
Ragdoll
搞清楚傳統(tǒng)骨骼動(dòng)畫(huà)之后,Ragdoll的原理也就十分容易理解了。要想為人物添加Ragdoll效果,只需要在模型骨骼上掛載合適大小的碰撞體及剛體組件,讓骨骼運(yùn)動(dòng)受物理模擬驅(qū)動(dòng)(而非動(dòng)畫(huà)驅(qū)動(dòng)),即可實(shí)現(xiàn)基于物理效果的布娃娃系統(tǒng)。
Unity 原生Ragdoll
Unity原生是提供Ragdoll功能的,我們可以右鍵模型Prefab -> 3D Object -> Ragdoll...

按提示把骨骼對(duì)應(yīng)Transform拖入即可,注意的是,骨骼一般以髖關(guān)節(jié)為基礎(chǔ),大概在人物腰部偏下 配置好后,Unity會(huì)自動(dòng)生成各肢體碰撞體,之后我們可以手動(dòng)調(diào)整碰撞體形狀以適應(yīng)模型

這時(shí)我們?cè)龠\(yùn)行游戲,發(fā)現(xiàn)人物已經(jīng)可以像布娃娃一樣癱倒了。
Unity原生的布娃娃系統(tǒng)功能非常簡(jiǎn)單,我們可以點(diǎn)進(jìn)之前配置有碰撞體的骨骼節(jié)點(diǎn)觀察一下。 可以看到肢體骨骼只是增加了一個(gè)RigidBody和Collider用于物理模擬,同時(shí)用CharacterJoint連接肢體模擬關(guān)節(jié),剩余全部交給Unity物理系統(tǒng)進(jìn)行模擬。
原生 Ragdoll 系統(tǒng)不足
看過(guò)Unity Ragdoll系統(tǒng)后,很明顯能發(fā)現(xiàn)該套系統(tǒng)功能較為簡(jiǎn)單,有很大不足
- 碰撞體、剛體等組件直接掛載在骨骼物體上,影響骨骼結(jié)構(gòu)的簡(jiǎn)單性,增加了耦合度
- 沒(méi)有Animator組件,意味著該Ragdoll系統(tǒng)只能單純受物理驅(qū)動(dòng),無(wú)法與動(dòng)畫(huà)融合(因此Unity官方也建議僅將該系統(tǒng)用于角色死亡時(shí)表現(xiàn))
- 狀態(tài)切換很困難、難以擴(kuò)展,且缺乏過(guò)渡(比如需要多套ragdoll不同表現(xiàn)時(shí),要修改碰撞體和剛體參數(shù)同時(shí)控制啟用)
Ragdoll Mecanim Mixer
Ragdoll Mecanim Mixer 插件正是為了解決上面的這些痛點(diǎn)而出現(xiàn)的,對(duì)于這些問(wèn)題,該插件都實(shí)現(xiàn)了很好的解決方案(該插件可在Asset Store購(gòu)買,目前Unity最好的Ragdoll插件之一)
- Ragdoll碰撞體與骨骼分離,不直接關(guān)聯(lián),降低耦合度
- 基于分離結(jié)構(gòu),可以分別計(jì)算物理變換與動(dòng)畫(huà)變換,并實(shí)現(xiàn)融合
- 基于一套R(shí)agdoll碰撞體可以預(yù)設(shè)多種狀態(tài),切換簡(jiǎn)單且可控制過(guò)渡平滑度
官方文檔:https://assetstore.altinqiran.kz/ramecan-mixer/files/GUIDE_ENG.pdf
該插件主要由兩個(gè)腳本組成
- Ragdoll Constructor
- Ramecan Mixer
Ragdoll Constructor
這個(gè)腳本主要用來(lái)為角色配置Ragdoll碰撞體及相關(guān)信息 掛載上腳本后,首先我們需要選擇為哪些骨骼創(chuàng)建碰撞體,規(guī)則和Unity原生Ragdoll基本一致。 選好后我們可以手動(dòng)創(chuàng)建一個(gè)Ragdoll Avatar(Scriptable Object),用來(lái)保存配置信息(選擇已有配置可以避免每次重復(fù)設(shè)置)

之后我們就可以為每個(gè)骨骼設(shè)置碰撞體大小、質(zhì)量、關(guān)節(jié)可活動(dòng)范圍等配置
[圖片上傳失敗...(image-88e4e9-1661398137783)]
配置好Create后,我們就可以看到player外出現(xiàn)一個(gè)容器,其中Ragdoll作為單獨(dú)的物體進(jìn)行管理,與角色本身解耦

Ramecan Mixer
創(chuàng)建好Ragdoll后,我們可以看到player身上自動(dòng)添加了一個(gè)RamecanMixer組件,這個(gè)組件主要負(fù)責(zé)控制多種狀態(tài)切換及動(dòng)畫(huà)融合功能,可以配置每個(gè)骨骼的詳細(xì)參數(shù),可以參考官方文檔,較容易理解

- 當(dāng)不需要Ragdoll物理效果時(shí)可以選擇 Is Kinematic 和 Only Animation,完全交由動(dòng)畫(huà)驅(qū)動(dòng)
- 當(dāng)需要Ragdoll物理效果時(shí)取消勾選 Is Kinematic,可以配置每根骨骼的詳細(xì)參數(shù)和角度限制
- 參數(shù)配置參考 (模擬尸體)見(jiàn)最后一節(jié)
配置好后,我們可以添加一個(gè)新的狀態(tài)進(jìn)行保存,之后可以用腳本控制切換 RamecanMixer.BeginStateTransition(Name)
RamecanMixer 原理分析
RamecanMixer 插件能夠?qū)崿F(xiàn)ragdoll與骨骼分離、實(shí)現(xiàn)動(dòng)畫(huà)融合等效果,其物理模擬依然是基于 Unity 物理引擎,主要在于其新增融合算法,并不難理解
在 Bone.cs 中我們可以看到對(duì)于Ragdoll骨骼的詳細(xì)定義,其中兩個(gè)參數(shù)可以留意一下
- animTransform
- physTransform
很明顯,Ragdoll 骨骼分別記錄了當(dāng)前由動(dòng)畫(huà)驅(qū)動(dòng)的骨骼 Transform(也就是模型骨骼),以及由物理驅(qū)動(dòng)的 Ragdoll 骨骼Transform (位于Ragdoll物體下的一系列碰撞體)
在 RamecanMixer.cs 中,可以看到實(shí)現(xiàn)物理效果及與動(dòng)畫(huà)融合主要遵循以下流程
- FixedUpdate() 中進(jìn)行關(guān)于 RigidBody 的物理運(yùn)算,主要是在 rigidbody 與動(dòng)畫(huà)骨骼出現(xiàn)偏差時(shí),通過(guò)對(duì) rigidbody 施力的方式去“彌補(bǔ)”差距,這樣可以實(shí)現(xiàn)物體的“慣性”效果
- Update() 中只進(jìn)行簡(jiǎn)單的賦值操作,記錄上一幀動(dòng)畫(huà)骨骼的變換信息
- LateUpdate() 中進(jìn)行的是核心的動(dòng)畫(huà)融合運(yùn)算,同時(shí)會(huì)基于前一幀剛體變換與當(dāng)前幀剛體變換進(jìn)行插值,實(shí)現(xiàn)平滑過(guò)渡
有興趣的可以仔細(xì)閱讀插件源碼,配有注釋比較容易理解
Ragdoll 參數(shù)配置心得
上面介紹了 Ragdoll 實(shí)現(xiàn)原理,但是要想實(shí)現(xiàn)較好的模擬效果,需要對(duì)各個(gè)骨骼進(jìn)行詳細(xì)配置,同時(shí)反復(fù)耐心的調(diào)試,最終才能達(dá)到想要的效果,這里可以對(duì)一些重要參數(shù)提供一些參考,主要用于模擬的角色死亡效果
質(zhì)量配比
要實(shí)現(xiàn)較好的布娃娃效果,最重要的是各骨骼的質(zhì)量分配,這里建議以實(shí)際人體的質(zhì)量分配為基準(zhǔn)
- 頭部 – 7.30%
- 軀干(胸部,背部和腹部) – 50.80%
- 大腿 – 9.88%
- 小腿 – 4.65%
- 上臂 – 2.7%
- 前臂 – 1.60%
- 腳 – 1.45%
- 手 – 0.66%
大腿等四肢,均指單條質(zhì)量。人體總重設(shè)置60-100KG之間較為合理

即設(shè)置 Ragdoll 骨骼質(zhì)量時(shí)不要嚴(yán)格遵循實(shí)際人體質(zhì)量分布,要在實(shí)際質(zhì)量的基礎(chǔ)上乘以對(duì)應(yīng)百分比,這個(gè)系數(shù)從髖部開(kāi)始向上下逐漸遞減 實(shí)際測(cè)試效果確實(shí)比嚴(yán)格遵循實(shí)際質(zhì)量分布更為符合直覺(jué)
RamecanMixer參數(shù)
- 開(kāi)啟self Collision
- Rotation Accuracy設(shè)為0.2或更低(保證關(guān)節(jié)靈活度)
- 角度限制開(kāi)啟(具體角度在Construct階段已配置好,建議參考人體關(guān)節(jié)可動(dòng)范圍)
- Joint Drive 中 Spring Rotation設(shè)為較低數(shù)值,保證關(guān)節(jié)可以擺動(dòng),數(shù)值較高會(huì)導(dǎo)致關(guān)節(jié)較硬(會(huì)努力回彈到原始形態(tài))
總結(jié)
Unity 實(shí)現(xiàn) Ragdoll 效果還是較為容易的,尤其是在現(xiàn)成插件的基礎(chǔ)上,我們要做的主要工作就是詳細(xì)配置 Ragdoll 參數(shù),使其符合我們希望的效果。