Impacter 與 Unreal | 利用游戲物理控制 Impacter 插件

簡介
Impacter 是最近針對 Wwise 開發(fā)的一款撞擊建模插件原型(詳可參閱這篇博文)。在本文中,我將介紹如何使用 Impacter 來實現(xiàn)聲音并整合到采用 Unreal Engine 構(gòu)建的演示游戲中。接下來,我想先簡要介紹一下 Impacter 的主要功能,然后再深入探討怎么在 Unreal?中加以運用。在此,我們重點說說如何利用物理系統(tǒng)來驅(qū)動 Impacter 的 Mass 和 Velocity 參數(shù)。這里總結(jié)的要點具有普遍適用性,對其他游戲引擎來說也是一樣的。
Impacter

作為源插件,Impacter 可交叉合成不同聲音的分層,并向這些聲音應用物理變換。如需進一步了解有關(guān) Impacter 的詳細信息,請參閱這篇博文或相關(guān) SDK 文檔。在此,我們不妨先簡單看下它都有哪些主要功能:
交叉合成
用戶可將多個聲音加載到 Impacter 中,然后在內(nèi)部加以分析并拆分為兩個分層:Impact 和 Body。Impact 代表對象被撞擊時的初始碰撞。Body 代表對象在初始撞擊后的諧振。
您可以自由組合 Impact 和 Body 分層,并讓 Impacter 在每次播放時隨機選擇。
物理參數(shù)
Mass 代表被撞對象的大小。
Velocity 代表對象被撞擊的力度。
Position 代表對象被撞擊的位置。此參數(shù)由聲學模態(tài)現(xiàn)象啟發(fā)而來。通過調(diào)節(jié)位置可讓聲音的諧振產(chǎn)生細微變化。
Roughness 代表聲音的嘈雜度,其可通過向聲音的諧振應用頻率調(diào)制 (FM) 來實現(xiàn)。
Impacter Unreal Demo
Impacter Unreal Demo 旨在方便測試和演示 Impacter 在簡單游戲環(huán)境中的不同用法。在后面章節(jié)中,我會簡要介紹一些相關(guān)用例,并探討如何利用游戲物理來驅(qū)動 Impacter。
基礎(chǔ)應用 (Footstep)
演示游戲中 Footstep 的設(shè)置相當標準。Wwise 中有個包含不同地面材質(zhì)對應腳步聲的 Switch Container 以及用于控制該 Switch Container 的 "FootstepMaterial" State Group。Wwise 中的 FootstepMaterial 狀態(tài)由游戲中的地面材質(zhì)設(shè)定。

鑒于每個 Footstep Sound SFX 都包含 Impacter 實例,我們選擇了借助交叉合成來在音頻樣本的基礎(chǔ)上生成更多變化版本。不過,目前為止針對的都是典型的 Footstep 場景。


通過使用 Mass 和 Velocity 參數(shù),可以獲得更加復雜精細的效果。藉此,可確保腳步聲與不同角色大小協(xié)調(diào)一致。里面專門設(shè)有一個 "CharacterSize" RTPC,用于驅(qū)動各個腳步聲對應的速度和質(zhì)量。在 Unreal 中,"CharacterSize" RTPC 由角色對象的大小設(shè)定。另外,角色對象的大小還會反過來影響角色的運動速度和跑動動畫。藉此,可模擬從巨大笨拙角色過渡到小巧靈活角色的效果。通過將 "CharacterSize" RTPC 映射到 Impacter 中的 Velocity 和 Mass 參數(shù),我們可以輕松地在腳步聲中對此予以呈現(xiàn)。

對象碰撞
環(huán)境中的每個對象和表面都有對應的 Wwise Event。這些 Event 可觸發(fā)一個或多個 Impacter 實例。各個 Impacter 實例會將 Velocity 和 Mass 參數(shù)分別與 "ImpactVelocity" 和 "ImpactMass" RTPC 掛鉤。在發(fā)生碰撞時,游戲會驅(qū)動這些 RTPC。
在構(gòu)建 Unreal Demo 并集成 Impacter 時,最重要的一項任務就是在碰撞過程中查詢 Unreal 物理系統(tǒng),來為 Mass 和 Velocity 參數(shù)提供合理的值,以此確保 Impacter 聲音作出自然的回應。我們可以通過名為 ImpacterComponent 的自定義 SceneComponent Blueprint 來實現(xiàn)這一點。游戲中的每個 Actor Blueprint 類都包含 ImpacterComponent(一個或多個)。在兩個對象發(fā)生碰撞時,它們的 ImpacterComponent 會調(diào)用 ImpactComponentCollision。這時會計算 "ImpactVelocity" 和 "ImpactMass" RTPC 值,以便在針對每個對象觸發(fā) Impacter Event 之前發(fā)送給 Wwise。

在此,我們有必要明確一些術(shù)語。比如,靜態(tài)對象是指從不移動的對象,動態(tài)對象是指可在游戲世界中四處移動的對象。在兩個對象發(fā)生碰撞時,Unreal 中會觸發(fā)兩個碰撞 Event,并分別用于每個對象的 ImpacterComponent。

這樣的話每個對象都要處理碰撞。首先,"On Component Hit" Event 針對 ImpacterComponent 調(diào)用 CheckImpactComponentCollision。接著,CheckImpactComponentCollision 確認 Other Actor 是否包含 ImpacterComponent。若其包含 ImpacterComponent,則調(diào)用 ImpactComponentCollision。

為了闡明這一點,我們來看個槍彈與墻壁碰撞的具體例子。從墻壁的角度來說,撞擊對象(另一對象)為槍彈。從槍彈的角度來說,撞擊對象(另一對象)為墻壁。相較于槍彈撞擊墻壁,認為墻壁撞擊槍彈似乎有悖常理。不過,在本節(jié)余下部分牢記這兩種情境會很有用。這里的關(guān)鍵在于每個對象都會觸發(fā)與之對應的 Wwise Event。在計算 "ImpactVelocity" 和 "ImpactMass" RTPC 時,會同時使用自身和另一對象的物理特性。
因為游戲中的所有對象都會使用 ImpacterComponent,所以關(guān)鍵在于以合理且普適的方式實現(xiàn)由碰撞物理到 RTPC 值的映射。這樣便可直接利用對象的物理特性來驅(qū)動聲音,而無需聲音設(shè)計師執(zhí)行任何進一步的手動調(diào)節(jié)。只要聲音設(shè)計師合理調(diào)節(jié)了 Velocity 和 Mass 曲線,關(guān)卡設(shè)計師就可放心地設(shè)計、放置并更改對象,聲音自會作出恰當?shù)幕貞?/p>
講明了這些,下面就來看下 ImpacterComponent 如何在碰撞 Event 期間使用 ImpactComponentCollision 函數(shù)計算 RTPC 值。
Mass 和 Velocity
"ImpactMass" 和 "ImpactVelocity" RTPC 值分別在 GetImpactMass 和 GetImpactForce 中計算。它們?nèi)客ㄟ^ ImpactComponentCollision 進行調(diào)用。

Mass (GetImpactMass)
Mass 直接從 Unreal 物理系統(tǒng)獲取并用于動態(tài)對象(注意:我們需要為具有相應?Density?值的對象設(shè)置 Physical Material,以確保賦予對象以相應的 Mass 值)。靜態(tài)對象本身沒有 Mass 值,因為其并不需要模擬物理。對此,系統(tǒng)會賦予其一個明確的 Mass 值。對于墻壁和地板,在設(shè)置 "Mass" RTPC 值時,會依據(jù)碰撞過程中撞擊對象的質(zhì)量計算其 Mass 值。

Velocity (GetImpactForce)
我們當然可以將對象的速度直接映射到 Impacter 中的 Velocity 參數(shù)。但是,對于體積小、重量輕的對象,這樣產(chǎn)生的撞擊聲過于響亮。比如,在一個柔軟的小球以足夠快的速度與金屬表面發(fā)生撞擊時可能會導致表面觸發(fā)巨大的撞擊聲。為此,最好將撞擊的力度映射到 Impacter 中的 Velocity 參數(shù)。所以,除速度外,我們還要使用動量(速度 x 質(zhì)量)。這樣的話,重量較輕的對象會產(chǎn)生較低的 "ImpactVelocity" RTPC 值。撞擊聲也會因而變得更加柔和。另外,在計算各自的 "ImpactVelocity" RTPC 值時,也要考慮兩個對象的動量。最后,我們還可直接將密度引入到映射中,確保質(zhì)地較軟的對象產(chǎn)生更為柔和的撞擊聲。
跟質(zhì)量一樣,速度的計算會因撞擊對象是動態(tài)還是靜態(tài)而略有不同。在撞擊對象為靜態(tài)時,使用 ImpactedByStaticObject 函數(shù)計算力度。在撞擊對象為動態(tài)時,使用 ImpactedByDynamicObject 函數(shù)計算力度。
ImpactedByStaticObject

在此,我們通過將被撞對象的動量乘以撞擊對象的密度來獲取 "ImpactVelocity" RTPC 值。記住,這里的撞擊對象是墻壁或地板。
ImpactedByDynamicObject

在此,我們使用各個對象的動量之和,其依據(jù)密度當中的最小值計算。注意,在這種情況下,被撞對象有可能是靜態(tài)的。這時的動量為 0,動量之和等于撞擊對象的動量。
為了便于理解,不妨將各種情形列在表格中。圖 1 顯示了如何針對不同的碰撞情形計算 "Velocity" 和 "Mass" RTPC。注意,兩個靜態(tài)對象永遠不會發(fā)生碰撞。

圖 1:RTPC 計算矩陣
測試和微調(diào)
在完成這些映射設(shè)置后,接下來便可將槍彈發(fā)射到表面上并測試聲音效果。

聽起來效果很差!這是因為當槍彈在地板上滾動時 Unreal 物理系統(tǒng)連續(xù)發(fā)送了多個碰撞 Event。鑒于槍彈滾動并不一定具有獨立的撞擊 Event,我們當然可以直接針對地面禁用撞擊聲,或者使用不同的插件(如 SoundSeed Grain)來實現(xiàn)滾動聲。不過,我們發(fā)現(xiàn)其實可以利用連續(xù)碰撞的優(yōu)勢,來模擬物體在大量輕微撞擊當中滾動的聲音(比如撞擊地面并滾動的聲音)。為此,我們不妨先來限制 ImpacterComponent 觸發(fā) Wwise Event 的速率。

現(xiàn)在聽起來沒剛才那么差了,但節(jié)奏太過緊湊,聽起來不自然。為了解決這一問題,我們可以為 Wwise Event 間隔時段增添一些隨機性。為此,我們來在每次重置計時器時向間隔時段施加隨機偏置。

現(xiàn)在聽起來好一點了,但槍彈滾動過程中的重復撞擊對滾動運動來說有點過了。聽起來好像是有人在連續(xù)撞擊地板一樣。為了解決這一問題,我們可以把運動的方向加入進來。具體來說,就是使用對象的速度矢量和從對象中心到表面上撞擊點的矢量之間的點積。說起來有些拗口。這里有個示意圖,各位可以看一下。

d?=?v.i。其中,v?= 速度矢量,i?= 從對象中心到表面上撞擊點的矢量。
在此,我們依據(jù)?d?來計算 "ImpactVelocity" RTPC 值。

若對象直接朝著撞擊點運動,則?d?= 1。若槍彈在地板上滾動,則 d 相對較低。這時的 RTPC 值會減小。

現(xiàn)在的聲音整合效果得到了進一步的改善。我們可以清楚地聽出槍彈最初在地板上彈跳以及隨后在地板上滾動之間的區(qū)別。
注意,d?因數(shù)的加入將改進其他情形以及在地板上滾動時的 RTPC 計算。比如,在快速移動的對象只是從另一對象的側(cè)面擦過而非與其迎頭相撞時。對于動態(tài)撞擊(兩個對象都在移動),每個對象都有?d?值。這時可以取這些值當中的最大值并使用其來計算兩者的 "Velocity" RTPC 值。對于靜態(tài)對象(地板和墻壁),d?= 1(最大值)。所以,在撞擊對象為靜態(tài)而被撞對象為動態(tài)時,會默認使用動態(tài)對象的?d?值。

打破規(guī)則
Impacter 本來是專門為某一類特定的聲音設(shè)計的。其算法假定振幅包絡(luò)呈指數(shù)級衰減,而且這當中有一個主要的瞬態(tài)區(qū)域。也就是說,聲音“看起來”是這樣的:

不過,我們也可試著將其用于其他類型的聲音。在 Impacter Unreal Demo 中,我加入了一些碎裂聲和粉碎聲。它們包含不止一個瞬態(tài),因而打破了算法的假設(shè)。

這里的問題是不同聲音的振幅包絡(luò)存在明顯的差異。如此一來,Body 分層(諧振部分)中便有可能會產(chǎn)生不自然的鳴響聲。振蕩器和濾波器組的振幅遵循原始聲音的振幅包絡(luò)。倘若與具有截然不同的振幅包絡(luò)的聲音的 Impact 分層結(jié)合在一起,聽起來就會很假。

針對此類情況,我們專門在 Impacter 的 UI 中添加了“啟用(inclusion)”復選框。藉此,可在針對一組聲音嘗試交叉合成時棄用存在問題的撞擊/模型組合。
在 Unreal 中,我添加了可在發(fā)生力度足夠大的撞擊時破壞的 Mesh 來構(gòu)建可粉碎的物塊。跟撞擊聲一樣,碎裂聲也包含 Impacter 實例。這些碎裂聲會將 Mass 和 Velocity 參數(shù)與 RTPC 掛鉤。

除此之外,在實現(xiàn)這種破壞聲時還可讓各個碎片來觸發(fā) Wwise Impacter 聲音,以此模擬物體碎裂成片并與環(huán)境以及彼此發(fā)生撞擊的效果。這樣的話,多個單獨的撞擊聲會結(jié)合在一起,游戲中發(fā)生的物理交互會直接生成碎裂聲/粉碎聲。Unreal Demo 中可破壞的箱體便是如此。最初,我使用了碎裂聲并設(shè)為在箱體碎裂時觸發(fā)。

這個碎裂聲存在問題,因為其具有截然不同的振幅包絡(luò)且包含多個瞬態(tài)。通過以上片段可以聽出,大箱體碎裂時能聽到多個瞬態(tài),但并沒有與此對應的物理交互。為此,我決定將 ImpacterComponent 與箱體的各個碎片綁定。這些 ImpacterComponent 最初處于非活躍狀態(tài)。在箱體碎裂時,各個碎片上綁定的 ImpacterComponent 會變?yōu)榛钴S狀態(tài),并開始對碰撞作出回應,進而觸發(fā) Wwise Event。如此一來,在箱體碎裂時,源自各個碎片的撞擊便會自然生成碎裂聲/粉碎聲。

位置映射
在大多數(shù)情況下,會為 Position 參數(shù)應用隨機化處理,來在整個 Unreal Demo 當中增添聲音的多樣變化。Position 參數(shù)可通過減小特定濾波器和振蕩器的增益來改變諧振。同時,將基于頻率的非線性增益斜線應用于聲音的 Body 分層。Position 參數(shù)可以控制這些內(nèi)部增益斜線的位置。也就是說,通過調(diào)節(jié)位置可讓聲音的諧振產(chǎn)生細微變化。在將位置設(shè)為 0 時,聲音具有全諧振特性。這時不會應用任何增益衰減。在位置由 0 變?yōu)?1 時,內(nèi)部增益斜線會逐漸減小和增大峰值頻率的增益。

在 Impacter Demo 中,寬大的玻璃墻壁會將撞擊位置和墻壁中心之間的距離映射到 "ImpactPosition" RTPC。這種映射是逆向的,所以角落和邊緣的諧振最強,而且在撞擊向中心移動時不同的峰值頻率會被衰減。

要點總結(jié)
在充分考慮從游戲物理到 RTPC 的映射后,我們可以靈活運用 Impacter 這款工具來整合各種撞擊聲。下面是在利用 Impacter 整合聲音時需要牢記的一些基本原則:
整體設(shè)計
結(jié)合 Mass 和 Velocity 參數(shù)測試聲音,確保在與游戲物理集成時得到充分體現(xiàn)。
活用力度
Impacter 中的 Velocity 參數(shù)應當由碰撞的力度驅(qū)動。很多因數(shù)都會對此產(chǎn)生影響,包括兩個對象的密度和動量。
變換位置
要想最大限度地增添聲音的多樣變化,最好對 Position 參數(shù)進行隨機化處理。藉此,可讓聲音的諧振產(chǎn)生細微變化。這對彈擊聲或腳步聲來說特別有用。?
打破規(guī)則
雖說本來是專門為撞擊類聲音設(shè)計的,但不妨試試其他輸入會有怎樣的效果。不過,在添加特別長的樣本時要注意。分析階段對簡單撞擊來說很快,但較長的聲音可能會比較費時。
稍后還會發(fā)布第三篇有關(guān)通過交叉合成實現(xiàn)多樣變化的博文。敬請期待!

肖恩·索拉漢(SEAN SORAGHAN)
軟件開發(fā)工程師
Audiokinetic
肖恩·索拉漢 (Sean Soraghan) 目前就職于 Audiokinetic,是一名軟件開發(fā)工程師,主要從事 Wwise 設(shè)計工具開發(fā)以及 Unity 和 Unreal 游戲引擎集成工作。在此之前,他拿到了工程學博士學位,重點研究音樂音色的表示法和視覺化。另外,還協(xié)助舉辦過大型聲音視覺裝置展會。他喜歡在閑暇之余開發(fā)各種游戲和工具。
