游戏角色口型老是对不上?这里有一个高效解决方案
編者按:本文將為大家介紹游戲制作過程中口型同步的常規制作方法,以及如何通過新的解決方案,高效的在Unreal以及Unity中創建原型與測試效果。
一個角色的性格和形象特征主要凸顯在三點上:語音、動作以及表情。
對于語音和動作,通過使用合適的聲優以及動作捕捉或動作制作,我們能夠獲得非常好的角色語音和動作特征,但如果沒有口型動作,我們在游戲中往往會覺得該角色在劇情表現中缺失了一部分靈魂,也會使得游戲的代入降低不少。
為了解決這一問題,在當前傳統的口型同步方案中主要有兩種:全系列動作表現,以及跟隨語音音量變化。
?
當前口型同步方案有兩種,全系列動作表現以及語音音量變化。
1.1 全系列動作表現
所謂全系列動作表現,指的是我們游戲中用到的所有和口型或表情相關的所有內容均由美術制作效果,將其作為一個動作進行輸出,當需要使用該表情或口型時,調用相關的動作來達到表現的效果。
?
這種方式使得角色表情豐富,游戲代入更深。但是也面臨一些問題:
?
- 制作量極大,美術需要針對每一句語音制作對應的動作,當語音較多時制作量太大,對于普通廠商來說是一個非常難以解決的問題。
- 游戲動作邏輯復雜,因為輸出方式以動作進行輸出,因此當需要進行表現時就要考慮如何在不同的環境下播放相關的動作,相對來說邏輯較為復雜。
綜合來看,雖然直接使用動作進行制作的效果會更加自然但是成本和工作量太大,對于大量語音的游戲不太實用。
1.2 語音音量變化
所謂語音音量變化指使用語音的音量,來控制游戲內口型的張閉,以音量的RMS進行動態的變更,使得模型口型匹配語音。
?
這種方式非常簡單,易于使用,但是分析太過簡化,僅僅使用RMS去控制口型形狀變化維度太低,沒辦法實現復雜的口型效果。
?
- 雖然制作量少,但是表現力較差。
這種方式對于精品化游戲沒有太大的幫助,因為分析有限所以能夠變化口型的維度太低表現力自然較弱。
我們可以看下面的動態效果:
?
從效果中我們明顯看出,如果單純的使用RMS去控制口部形狀變化表現力較差,而且會有非常明顯的抖動效果,因為音量的變化是非常迅速的,當口型每幀刷新變形效果也使得口型變動較為鬼畜,影響觀賞效果。
那么這兩種方式都有各自的優缺點,無論是成本還是效果都不是最佳選擇,我們還有其他方法嘛?
這將是本文說明的重心——ADX LipSync口型解決方案。
?
ADX LipSync是Criware公司推出的,針對其音頻中間件ADX2的口型解決方案。
實際上除了可以和音頻中間件ADX2連用外,還能夠單獨進行使用。
2.1 LipSync說明
LipSync是最新推出的,針對口型匹配的新解決方案。能夠實時以及預先分析聲音素材,得到聲音素材所包含的信息后,將其運用于模型上,通過變更模型的變形效果,綜合控制口型的變化,以達到口型和語音匹配的目的。
LipSync主要有兩種應用模式,實時解析和預先分析。
?
- 實時解析可以通過話筒錄入實時分析錄入的聲音內容,進行分析最終得到相關的口型數據,進行模型變形匹配聲音口型。
- 預先分析是通過將已經錄音處理好的wav文件進行分析,得到相關的分析數據,當播放相關的wav文件時,可以使用事先分析好的數據進行模型的變形以匹配聲音口型。
LipSync也擁有兩種應用方法,單獨使用和與ADX2聯合使用。
?
- 單獨使用是LipSync單獨應用,直接使用LipSync進行聲音分析,最終得到口型數據和效果。
- 與ADX2聯合使用,這種方式LipSync作為ADX2的插件使用,能夠分析ADX2中Cue中Track軌道上的波形文件,生成相應的聲音數據。分析相應的數據也可以事先分析或者實時分析,這種應用方式稱為ADX LipSync也是本文中介紹的重點內容。
想要使用ADX LipSync口型同步,我們首先需要能夠變更口型的模型,下面將通過3D Max簡單的介紹如何制作口型數據。
2.2 模型口型數據創作
首先我們需要創建好一個包含口型的模型,然后導入到3D Max中:
?
選中模型后按住Shift復制一個副本。
?
創建變形器。
?
在創建的副本模型上更改相關變形效果。
?
回到原始模型,選擇變形目標創建變形數據,完成后更改數據的值,我們就能夠看到變形效果在模型上產生了。
?
選擇當前模型,進行導出,導出后的模型就可以為我們的口型效果提供變形數據。
?
到此為止我們的模型數據就制作完成。
2.3 聲音數據處理
完成了模型處理后,我們需要準備聲音部分的處理。
ADX LipSync是跟隨音頻中間件ADX2進行連用,因此我們可以使用音頻中間件ADX2來進行相關處理。
當使用當使用ADX LipSync時,將素材拖入到Track后,就能夠看到聲音文件對應的口型數據分析結果。
?
如上圖,分析結果位于圖片的右下方,我們可以看到相關的高度和寬度數據,這些是自動分析的結果,自動分析結果我們可以進行手動更改。
經過分析后,我們主要產出兩種分析數據:
?
- 寬度高度模式,這種分析結果數據,對應于口型變化的寬度和高度結果,通過對聲音進行分析,得到對應聲音時刻變化的寬度和高度曲線,同時可以在ADX2中進行高度和寬度曲線的調整,以應對自動分析不滿意的效果。
?
- 音素混合量分析模式,這種分析結果數據是分析語音中各個音素量的占比,通過占比決定各個音素口型的權重從而動態的變化模型變形效果,同樣如果對于自動分析結果并不滿意,則可以手動修改。
?
通過這兩種數據,我們可以變更口型變化效果,來實現口型同步。
注意:
?
- 對于寬度和高度模式,沒有任何語言限制,所有語種都可以使用,但是解析精度相對低。
- 對于因素量混合分析模式,和語種相關,目前提供日語的AEUIO幾個元音進行解析,因此對日語的匹配度較高。
在使用ADX LipSync時,會和ADX2一起連用,由音頻中間件ADX2導出資源文件,這些資源文件包含了音頻中間件中制作的聲音資源文件也包含了其中的口型數據結果。
完成了以上內容后,我們的資源文件就準備完成,下面我們將介紹如何使用這些資源文件來實現口型同步效果。
2.4 Unreal應用
準備好資源文件后,我們將資源文件導入到Unreal中主要包含兩個文件,首先是創建的變形數據的模型文件,導入后我們在Unreal中打開,可以看到如下內容:
?
我們可以看到,在3D Max中創建的變形數據已經顯示在Unreal中了。此時我們在Unreal中更改相關參數也能看到參數對模型產生的變形效果。
?
上圖顯示的是導入的ADX2的聲音資源文件,導入后會自動顯示出創建的Cue(事件)內容。
我們將使用這些Cue內容,以及相關接口創建藍圖,用以播放聲音時變更模型的變形效果完成口型和語音的匹配。
下面我們開始制作口型同步內容。
①藍圖類創作
選擇我們的模型文件,創建藍圖類:
?
同時創建Atom Component,Atom Component主要用于Cue的播放,由于Cue中包含wav信息,而ADX LipSync則是分析Cue中的聲音信息生成對應的口型數據,因此我們需要播放相關的Cue來同步口型。
②初始化LipSync
藍圖類創建完成后,我們要進行藍圖功能的創建,首先我們需要創建初始化LipSync相關邏輯,我們創建一個名稱為Set ADXLipSync的宏,該宏用于初始化LipSync,邏輯如下:
?
創建了構建Lips Atom Analyzer,并將其設置為變量,便于調用。并添加Init相關,需要注意的是Init必須要創建Attach前。
而后用Get Info并將Lip Width的值設置為參數的原因是當處于無聲狀態時,口型的寬度并不一定等于0,這些由美術在制作模型變形數據時決定。
初始化創建完成后,我們回到事件圖表中,并創建下面藍圖內容:
?
通過Event BeginPlay我們執行了Set ADXLipSync宏,初始化相關內容,同時我們Play Atom使得運行時能夠直接聽到聲音效果。
③口型分析模式創建
初始化完成后,我們需要創建口型分析模式,并且通過口型分析模式來決定我們怎么使用模型的變形效果,通過分析的聲音口型數據動態的變更模型的變形參數來實現口型變化效果。
因此我們創建兩個宏分別對應寬度高度模式,音素量混合分析模式,為了做對比,我們再創建一個宏用于音量控制。
?
寬度高度模式相關邏輯如下:
?
我們使用了Get Info的相關數據,使得Lip Width控制模型文件的LipWidthOpen參數,Lip Height控制模型的LipHeightOpen參數,使用Tongue Position控制模型的Tongue_Up參數,當Info的數據跟隨聲音進行變化時,能夠同時變更模型相關的各個參數值變化,引起口型變化。
音素混合量分析模式相關邏輯如下:
?
與高度寬度類似,只是使用的數據不同控制的模型變形參數不同,同樣可以控制模型的變形參數實現口型的變化。
音量模式相關邏輯如下:
?
音量模式我們創建的目的是為了進行對比,以此來通過模式切換非常方便的看到不同模式下口型的效果。
音量模式下,我們采用的是通過Bus中的Peak Leavels值來變更模型的LipWidthOpen以及LipHeightOpen參數。
通過上述步驟,我們完成了創建寬度高度模式、音素混合量分析模式以及音量模式的宏,下面需要創建如何使用這些宏來變化口型效果。
④界面顯示及其功能創建
我們想通過Unreal直接進行運行中更改模式,并且顯示相關Cue(事件)名稱以及當前的分析模式以便于我們進行測試和效果演示,因此我們創建一個UI控件藍圖,并添加以下內容:
?
完成后,我們選擇"TextBlock300"和"TextBlock492"并做如下的顯示TXT綁定內容:
?
同時創建兩個String類型的參數分別為:CueNameParam以及LipsyncModleNamePara用于存儲Cue的名稱和當前模式的名稱。
?
回到我們的藍圖類中,我們已經完成了3個宏的創建,并且擁有了相關UI,那么下面需要將UI創建在界面上,并且進行模式的更改:
?
如上圖所示,我們創建相關UI控件,使之顯示在運行中的場景中。
同時為了更改口型分析的模式,我們需要創建三個不同的bool類型變量。
?
這三個bool類型的參數用于我們的模式選擇。
我們再創建三個自定義事件,用于控制模式更改時的bool類型值變化以及創建的UI中的當前模式的顯示文本:
?
在上圖中我們可以看到,當執行不同的自定義事件時,會更改相關的bool參數值,同時會設置UI中的LipsyncModleNamePara參數顯示。
完成上圖中內容后,我們擁有了能夠改變bool值的參數,而我們想通過bool值參數來變化混合模式的類型,下面將做相關內容邏輯:
?
我們通過調用Event Tick使得每幀刷新,通過三個bool變量選擇最終的混合模式,而在混合模式中,由于每幀刷新,因此會不斷的根據Cue的聲音內容變更相關的info信息,從而每幀更改模型的變形參數,形成最終的口型效果。
完成上述內容后,我們僅僅是完成了各個口型模式的邏輯,以及如何選擇任意一個模式的邏輯,但是沒有選擇相關模式的觸發內容,因此我們回到UI控件藍圖中:
在控件藍圖中我們選擇如下的按鈕并且使用其點擊事件:
?
鼠標點擊后將會跳轉到事件圖表中,我們做如下的邏輯:
?
可以看到我們在控件藍圖中調用了剛才在模型藍圖事件圖表中創建的三個自定義事件,如此一來我們每次點擊按鈕都會按照順序執行三個自定義事件中的一個,以此來更改設定的bool參數值,從而在Event Tick調用時轉變調用的混合模式宏,驅動不同的模型變形參數效果。
注意:在上圖中的Sequence Flip是筆者自己定義的流程控制宏,用于每次執行時按照順序依次執行一條,如此反復,相關邏輯如下:
?
按照上述內容完成后,我們就可以得到每次點擊按鈕就會變化混合模式,當聲音播放時我們就能夠看到不同模式下口型變化效果進行對比和分析。
而各位在實際測試中會發現,當我們變更模式時有時候口型會變得非常大,這是因為在我們點擊按鈕變更模式時,所有數據依然是當前點擊時的數據,因此會被記錄并且保持不變,當使用其他模式時,其他模式下的聲音數據引起的口型變化效果和當前點擊時的口型變化值相疊加導致口型變大。
為了解決這一個問題,我們需要在點擊按鈕變化模式時,將所有變形效果重置為0,因此我們創建Reset宏,邏輯如下:
?
如上圖,Reset宏的作用是當執行該宏時,會重置所有模型的變形參數值,使得其回歸到0,當被其他聲音數據再次驅動時能夠不記錄前一個數據的值而引發口型變大效果。
同樣我們需要在Event Tick時進行處理:
?
如此一來,當每幀調用時,每次更改模式,都會觸發一次Finish為False而執行一次Reset,通過Reset我們將所有模型的變形數據還原修復口型變大的問題。
當完成上述內容后,針對如何使用ADX LipSync的介紹已經完成,我們可以通過上述內容測試和制作相關口型同步原型。
但筆者這里再進行一步優化使得能夠在運行中時刻測試不同語言在不同模式下的表現。
⑤優化內容
由于ADX LipSync是由聲音中間件ADX2創建的數據進行分析后得到的數據進行口型處理,那么我們可以創建相關的變量用于存儲不同語種的Cue內容,使得在運行中可以實時切換便于測試。
首先我們創建一個名稱為CueList,變量類型為Sound Atom Cue的數組,并將不同語言的Cue內容添加到數組中:
?
完成后我們再創建一個名稱為CueChoice的自定義事件,并添加如下邏輯:
?
其中從UI中獲得的Cue Index稍后介紹,需要在UI控件藍圖中進行創建。
創建上述的邏輯目的是為了當我們點擊一個按鈕時,能夠動態的選擇其上一個或者下一個CueList中的Cue進行播放,同時將Cue的名稱顯示在界面上。
CueIndex參數是需要在UI控件藍圖中進行創建,因此我們回到UI控件藍圖中,創建一個整型的名稱為CueIndex的變量:
?
此變量主要用于記錄當前的Cue的Index并且,當我們點擊按鈕時能夠動態的切換其數值,來變更將要播放的Cue Index從而更改和播放相關Cue。
為了能夠通過界面進行Cue的切換,我們需要對下面的按鈕進行點擊事件的邏輯創建:
?
創建的邏輯如下:
?
上圖中顯示通過CueIndex的值,當點擊按鈕時選擇增加或減少1,當超過或小于某個值時回到正確的索引范圍內,當然筆者這里使用的是具體的數字,更加常規的做法是需要在模型藍圖類中獲取CueList的Length,將其值傳入進行控制。
當點擊按鈕后,游戲買賣平臺會執行CueChoice的自定事件,同時將相關的Cue Index傳入模型藍圖類中用于選擇CueList中的Cue內容,并進行播放。
如此一來就完成了我們的Cue的切換,我們可以實時的切換Cue,并實時的更改模式來測試我們創建的原型效果。
我們還可以再在模型藍圖中和UI控件藍圖中創建如下邏輯,使得單機按鈕時進行當前Cue的再次播放,以此來方便觀察同一個語音在不同的模式下口型表現效果:
完成上述內容后,我們就能夠完整的完成一套原型,該原型能夠通過點擊按鈕切換口型分析模式,同樣可以更改播放的Cue內容來測試同一模式下不同語種的口型效果以及同一語種下,不同模式的口型效果。
最終完成效果參考:
?
可以看到,在不同的模式下的表現效果不同,Volume形式下表現較差,高度寬度模式可以較好匹配語音,而音素混合量模式則表現更加。通過語音內容的分析,我們得到口型數據,從而驅動模型的變形參數使之與語音同步匹配。
這種方式下效果較好,且成本很低非常適合大量語音口型同步制作。
2.5 Unity應用
與Unreal中類似,我們通過導入資源文件,在Unity中創建相關Object,并添加相關代碼,最終做出口型同步效果。同樣我們也將制作支持界面按鈕點擊切換模式與切換播放的語音。
①模型資源
當導入我們包含了變形參數的模型后,我們需要將其拖拽到場景中,并調節相關位置使之能夠在攝像機中被看到。
?
模型放在Hierarchy中以備后續調用。
②界面按鈕創建
我們希望能夠在運行時實時調整口型的分析模式,且實時更換播放的語音內容,因此我們可以通過創建按鈕來實現這些功能:
?
如上圖,創建6個界面按鈕,從上至下功能依次為:
?
- "Button_play":播放Cue(事件)按鈕,當按下按鈕時播放相關語音。
- "Button_stop":停止Cue(事件)按鈕,當按下按鈕時停止播放相關語音。
- "Button_>":切換Cue(事件)按鈕,當按下按鈕時將會切換播放的語音。
- "Button_<":切換Cue(事件)按鈕,當按下按鈕時將會切換播放的語音。
- "Button_textshowcue":顯示Cue(事件)名稱,當更換Cue時,顯示文本跟隨Cue名稱變化。
- "Button_modleselector":顯示當前口型模式,按下按鈕時將會切換模式且按鈕上文本將會跟隨轉變。
其中前四個按鈕為功能性質按鈕,按鈕點擊后會對應上述功能,但顯示的文本不變,第五個單純顯示Cue名稱,第六個是顯示和功能性按鈕,按下后將會對應功能且文本顯示也將發聲變化。
③聲音資源處理
準備好我們的模型和按鈕后,我們需要處理聲音資源,所有的聲音素材都經過中間件ADX2進行打包后倒入到Unity中,此時我們創建一個空的Object于Hierarchy中,并重命名為CRIWARE,同時點擊Add Component按鈕,創建Cri Atom組件腳本:
?
添加完成后,在Cri Atom中填寫相關acf,acb以及awb文件路徑,以備使用。
④口型模式
在接下來的步驟中,我們將處理口型模式與模型變形參數,使之能夠被我們正常的調用。
我們繼續在Hierarchy中創建一個空的Object并命名為:ModelControl,而后在其上點擊Add Component按鈕添加腳本組件:"Cri Lips Shape For Atom Source":
?
可以看到在該腳本中我們需要添加兩個內容:Cri Atom Source以及SkinnedMeshRenderer。
Cri Atom Source我們稍后添加,首先將SkinnedMeshRenderer添加完成,我們在Hierarchy中選擇之前的模型組件,將其拖拽到SkinnedMeshRenderer上完成添加:
?
添加完成后將會出現下面的內容:
?
此時點擊BlendShapeType就可以選擇寬度高度模式還是音素混合量分析模式,而在其下方的內容中點擊就可以選擇 我們之前在模型中創建的變形參數名稱。
?
將我們創建好的模型變形數據依次填寫完成,這樣就完成了不同口型模式下各個音頻分析的口型數據對應的模型變形參數的匹配。
我們再在ModelControl中通過Add Component添加一個Cri Atom Source組件。
?
完成后,我們選擇Hierarcgy中的ModelControl將其拖拽到之前創建的"Cri Lips Shape For Atom Source"腳本組件中的CriAtomSource中:
?
這樣一來,我們"Cri Lips Shape For Atom Source"需要的相關信息就已經添加完成,下面需要進行腳本處理。
⑤處理腳本
我們最終希望的效果是能夠在運行過程中切換口型模式,同時也能切換播放的語音內容,而Play和Stop按鈕也可以控制Cue的播放和停止,因此我們需要創建一個自定義腳本腳本內容如下:
?
在上面的腳本中我們主要進行了以下內容:
?
- 首先定義了acb,acb是聲音的資源文件,其中存儲了需要播放的所有Cue內容。
- 同時通過acb獲取了其中的cue內容,將其顯示在界面上。
- 創建了自定義的PlayCue,StopCue,SetSelectedCueIndexIncrease以及SetSlectedCueIndexDecrease方法,分別用于播放Cue,停止Cue以及選擇Cue內容,使用的是從acb中獲取的CueIndex。
- 創建了自定義的changeModle方法,用于點擊按鈕時能夠切換口型模式(寬度高度模式以及音素混合量分析模式)。
- 在changeModle方法中使用了SetBlendShapeWidthHeightAtSilence和setSetBlendShapeJapaneseAIUEOAtSilence方法,這兩個方法主要用于在切換模式時將相關的數據還原,使得口型變回基礎狀態。
完成腳本內容后,我們需要將創建的腳本方法與按鈕的點擊以及各個文本顯示相連接:
?
如此一來,我們的腳本內容和按鈕就可以進行使用了,運行場景來測試一下效果吧。
?
ADX LipSync使用簡便,又能夠和音頻中間件ADX2聯合使用,完美解決了當想使用音頻進行口型實時分析時,不能將音頻進入音頻中間件管理的問題。
同時分析的效果也相對較好,快速的幫助游戲項目完成非常好的口型效果表現。
總結
以上是生活随笔為你收集整理的游戏角色口型老是对不上?这里有一个高效解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实时光线追踪技术:业界发展近况与未来挑战
- 下一篇: 小游戏发布云测试工具,中小团队的“小又快