李卓真,郎誠廉
(同濟大學 電子與信息工程學院,上海 200331)
由于我國目前城市化的快速發(fā)展,道路交通的壓力越來越明顯[1]?,F(xiàn)代有軌電車是在傳統(tǒng)有軌電車的基礎上發(fā)展起來的先進公共交通制式,與傳統(tǒng)公共汽車相比,具有客運能力大、速度高、彈性靈活、舒適新穎、綠色節(jié)能等特點[2]。隨著現(xiàn)代有軌電車的蓬勃發(fā)展,對駕駛員的培訓日益提上議程,如何對駕駛員進行安全高效的培訓是未來城市交通體系中不可缺少的組成部分[3]。
在列車上,司機的主要職責是駕駛列車、到站后進行站臺操作、監(jiān)控列車運行狀態(tài)及保證乘客安全。司機通過安裝在列車上的監(jiān)控設備,對乘客動態(tài)進行實時監(jiān)控,以避免發(fā)生意外事故[4]。在列車駕駛模擬器中,也需要對這些監(jiān)控系統(tǒng)進行模擬[4]。這其中,列車乘客的動作仿真研究顯得非常重要[5]。
三維視景仿真技術是計算機技術的重要分支,是計算機技術、圖形圖像處理技術、多媒體技術、信息合成技術以及顯示技術等諸多高新技術的綜合運用。我國在上個世紀80年代末90年代初將三維視景仿真技術應用于城軌仿真中,主要是為司機培訓提供一種模擬駕駛平臺,平臺的三維視景通過地鐵列車運行時從司機室實景拍攝得到,通過疊加關鍵技術生成。比較有代表性的系統(tǒng)有:文獻[6]著重從場景模型的生成、動態(tài)場景的控制、視點變換、人物仿真等幾個方面研究了虛擬仿真技術與地鐵運行仿真系統(tǒng)的結(jié)合;文獻[7]就列車模擬駕駛器視景生成技術、計算機成像(CGI)視景系統(tǒng)功能、系統(tǒng)關鍵技術等作簡要闡述;文獻[8]從提高動態(tài)仿真效率和渲染速度的角度出發(fā),采用基于圖形與圖像的混合建模方法和細節(jié)層次(LOD)與紋理映射技術,實現(xiàn)了列車運行的三維動態(tài)視景仿真。本文在前人的基礎上,對人物進行場景上的支持,利用Character Studio進行人物動畫創(chuàng)建,使用AStar算法進行場景內(nèi)的自動尋路功能,規(guī)避障礙及各種險情的發(fā)生,以實現(xiàn)對駕駛員的培訓。
本文利用3ds MAX建模軟件構建了三維虛擬列車模型、人物的三維模型及基本動作模型,以Unity3D為應用平臺,以VC#2017為編譯器實現(xiàn)對三維模型的驅(qū)動控制,從而為現(xiàn)代有軌電車模擬駕駛提供場景支持。
本文以南京有軌電車麒麟線為模型,在此基礎上對車站、列車等場景進行建模仿真。選用3ds MAX建模軟件構建了三維虛擬列車模型、人物三維模型及基本動作模型,3ds MAX是一款三維建模與渲染的軟件,主要包含幀動畫制作、多邊形建模、曲面建模、材質(zhì)制作、模型優(yōu)化等功能。較其他建模軟件相比,3ds MAX具有操作簡單、渲染高端、三維動畫逼真、互操作性靈活等優(yōu)點。3ds MAX的模型導出格式很多,本文中,主要將max文件導出成FBX格式文件,然后導入到Unity3D中進行控制[9]。
虛擬有軌電車的建模有如下幾個步驟:
(1)在3ds MAX建模軟件中使用立面和平面比照參考,通過多邊形建模方法對列車進行精確建模;
(2)根據(jù)紋理數(shù)據(jù)和貼圖建立對應結(jié)構的材質(zhì)球;
(3)將材質(zhì)球賦給對應的結(jié)構模型,主要包括車內(nèi)客室座椅、玻璃窗、地板、立柱和扶手、照明系統(tǒng)及列車整體。
所建模的列車共5節(jié)車廂,其三維模型如圖1所示。
圖1 虛擬電車三維模型圖
在3ds MAX 中利用Character Studio創(chuàng)建角色動畫。對骨骼加載設定好的基本動作,然后將骨骼和人物模型綁定,可看到骨骼驅(qū)動3ds MAX模型的運動,這樣就可以創(chuàng)建一個有設定動作的人物模型。
1.2.1 創(chuàng)建人物動作
正常情況下,人物在列車內(nèi)產(chǎn)生的行為基本可以分為:行走(walk)、站立(stand)、坐下(sit down)、起立(stand up)等[10]。本文使用3ds MAX中的關鍵幀動畫功能創(chuàng)建了這幾個基本動作,并將這幾個動作加載到虛擬人物模型,從而可以實現(xiàn)人物的運動。
所謂的關鍵幀動畫,就是按照自己所想達到的動畫效果,選擇不同位置的幀,設置不同動作的式樣,在短時間內(nèi)設置盡量多的幀,然后連續(xù)播放。通過采用特殊的計算方法算得這些關鍵數(shù)據(jù),由此達到非常順暢的動畫情景。
1.2.2 人物文件的導出
本文選擇文件導出類型為Unity3D所支持的FBX格式。FBX主要有ASCII和二進制兩種編碼格式,ASCII編碼優(yōu)點是可通過代碼調(diào)整數(shù)據(jù),缺點是文件所占內(nèi)存較大,影響3D引擎渲染模型的速率,在場景模型數(shù)目過多的情況下,渲染速率過慢會嚴重影響運行的幀數(shù),視覺效果不好;二進制編碼的模型文件雖然不易修改,但是文件所占內(nèi)存較小。因此在本文中導入的模型為二進制編碼的FBX格式文件。圖2為導入的人物各個狀態(tài)。
圖2 各狀態(tài)的人物模型
在仿真過程中,使用了導航網(wǎng)格(NavMesh)來實現(xiàn)乘客的自動尋路過程。
在NavMesh方法中采用了AStar算法,其自動尋路的思路是將尋路區(qū)域劃分成小方塊用以存放在二維數(shù)組中。通常將起點所代表的方塊記為A,終點所代表的方塊記為B,障礙物則用陰影表示。計算并比較從起點A到終點B的成本便可找到一條最優(yōu)的路徑,AStar算法流程如圖3所示。其具體方法如下:
圖3 ASrar算法流程圖
(1)從起點A開始,把它作為待處理的方格存入一個“開啟列表”,開啟列表就是一個等待檢查方格的列表。
(2)尋找起點A周圍可以到達的8塊方格, 將它們放入“開啟列表”,設置它們的“父方格”為 A。
(3)從“開啟列表”中刪除起點 A, 并將起點 A加入“關閉列表”,“關閉列表”中存放的都是不需要再次檢查的方格。
在開啟列表中計算每個方格到達終點B的通過成本,計算公式為:
在公式(1)中,G表示當前方格到起始方格的估量代價,H表示當前方格到終點的代價(H有很多計算方法,這里設定為上下左右移動)。
(4)從“開啟列表”中選擇F值最低的方格設為C,將其作為新的起點,并將C放入“關閉列表”。
(5)檢查方格C相鄰的方格,但不包括障礙物和“開啟列表”中的方格。判斷“開啟列表”中是否存在這些方格,若不存在,則將其加入至“開啟列表”,同時計算每個方格的F、G的值(H值始終為定值,不用計算),并將C設置為其“父方格”。
(6)若某個相鄰方格D已經(jīng)存在于“開啟列表”中,則計算經(jīng)過C到達D的路徑的G值,若新的G值小于舊的G值,將D的“父方格”改為方格C,然后重新計算F、G的值,反之不用對方格D進行任何操作。
(7)由于方格C相鄰且可到達的方格除了障礙物之外都在“開啟列表”中,因此可以選擇方格D作為新的起點并將其設置為父方格,此種情況默認不允許斜向走至障礙物相鄰的方格。
如此循環(huán),直至“開啟列表”中出現(xiàn)了終點方格B后,結(jié)束循環(huán)。連接所有“父方格”即為從起點A到達終點B的最低成本路徑,如圖4所示。
圖4 最優(yōu)路徑模型
導航系統(tǒng)可以讓人物在場景里智能地移動、繞過障礙等,本文使用NavMesh來解析環(huán)境。
2.2.1 設置NavMesh
在Insprector窗口中點擊Static下拉菜單,勾選靜態(tài)導航(Navigation Static),在Navigation Area下拉框里選擇可行走(walkable),即設置地面為可走區(qū)域。同時,乘客在尋路過程中要避免碰撞到柱子、閘機、墻、座椅、樓梯等障礙物,所以在Navigation窗口中依次選擇這些障礙物,勾選Navigation Static,設置為不可行走(Not Walkable)。
當車廂內(nèi)物體類型設置完畢后,需要對場景進行烘焙。烘焙的目的是保存當前的導航網(wǎng)格設置,并且保存可行走區(qū)域和障礙物的信息。烘焙分為2種,動態(tài)烘焙和靜態(tài)烘焙。其中動態(tài)烘焙會根據(jù)當前場景的變化而實時更新導航網(wǎng)格,這種方式適用于障礙物需要移動的場景,比如模擬戰(zhàn)爭游戲等;靜態(tài)烘焙是在場景編輯狀態(tài)下設置好導航網(wǎng)格,在場景運行狀態(tài)下不再更新,這種方式適用于障礙物以及可行走區(qū)域位置和大小不變等場景,比如室內(nèi)探險、捉迷藏等游戲。因此相對于動態(tài)烘焙,靜態(tài)烘焙消耗的資源更少,場景運行的幀數(shù)會更高。由于在場景運行時地鐵車站里的柱子、閘機、座椅、樓梯等障礙物的位置和大小不會發(fā)生變化,所以本文采用靜態(tài)烘焙方式,烘焙之前需要根據(jù)乘客的大小來調(diào)整烘焙的參數(shù)。
在開發(fā)過程中,乘客模型身高設計為1.5 m~1.9 m,調(diào)整合適的烘焙參數(shù),在Windows中打開Navigation窗口,將導航代理半徑(Agent Radius)參數(shù)設置為0.1,單位為m,因為車廂寬度為1 m,如若導航代理半徑設置的數(shù)值太大,為躲避各種障礙物則幾乎無可行走區(qū)域。最后點擊烘焙即可完成導航網(wǎng)格設置,烘焙結(jié)果如圖5所示,地面藍色為可行走區(qū)域。
2.2.2 設置導航代理
導航代理可以理解為去尋路的主體,設置方法為:在人物模型上為其添加NavMeshAgent組件,并通過相應的腳本進行驅(qū)動。
圖5 導航網(wǎng)格模型
對于動畫的控制可以選擇Animation或Animator,由于Animation只能單一地控制一個動畫的播放,而Animator可以在不同動畫之間進行切換,設置動畫狀態(tài)機,包括從腳本控制的狀態(tài)機、混合樹和事件來進行設置。所以本文采用Animator組件,乘客的動畫狀態(tài)機主要包含walk、stand兩個動畫,動畫之間為雙向箭頭,且參數(shù)列表設置了walk的bool值,方便程序?qū)赢嫚顟B(tài)機的控制。
使用NavMesh結(jié)合動畫系統(tǒng)可使人物在車廂內(nèi)實現(xiàn)角色的移動。創(chuàng)建空物體可以給指定人物設定target,通過調(diào)用agent.destination函數(shù)給人物設定目標位置,使人物進行尋路。當距離終點0.1 m時會更新終點的坐標,以維持行走的狀態(tài)。
為了實現(xiàn)車門開關的功能,需要對車門模型進行平滑移動,這里選擇一種簡單輕量的插件iTween來實現(xiàn)。iTween的核心原理是根據(jù)不同的需求,通過多種插值方法來自動生成起始點與終點之間的中間值,實現(xiàn)不同的效果。iTween中的大部分方法除了簡單的輸入?yún)?shù)外,都會重載一個輸入?yún)?shù)為哈希表(Hashtable)型變量的方法,通過哈希表可以對方法進行更加詳細的控制。
在此處我們需要使車門進行平滑移動,可以利用iTween的MoveTo方法來實現(xiàn)。MoveTo方法可以在指定的時間內(nèi)不斷改變物體的位置,直到達到目標位置,定義如下:
MoveTo(GameObject target,Vector3 position,float time)
MoveTo(GameObject target,Hashtable args)
其中,target為需要移動的物體,position為目標位置,time為經(jīng)過的時間。為了使車門能勻速移動,我們通過之前提到的哈希表來將物體的移動方式設定為線性。程序中調(diào)用MoveTo方法的一段代碼如下:
iTween.MoveTo (this.gameObject, iTween.Hash("x", 1.0f, "z", 0, "time", 3, "islocal", true, "easetype",iTween.EaseType.linear));
其中,this.gameObject是所掛在的組件,iTween.Hash是iTween中方便用戶創(chuàng)建哈希表的方法。x表示目標位置的x坐標,z表示目標位置的z坐標,time表示在多久后移動到目標位置,islocal為采用世界坐標還是與父物體有關本地坐標,easetype表示物體移動的類型,這里選擇iTween內(nèi)置的線性方式,即為勻速運動。車門移動如圖6所示。
圖6 模擬車門關閉及開啟
乘客分為動態(tài)乘客和靜態(tài)乘客。靜態(tài)乘客主要集中在列車上,不參與尋路過程。為了模擬乘客上下車,這里采用一種簡單的方式。以每個車廂模型為父物體在車門外創(chuàng)建若干空的子物體,在開始時將乘客模型生成在車廂內(nèi),需要下車時就讓乘客走向這些子物體。當列車未進站時,動態(tài)乘客在路面的導航網(wǎng)格內(nèi)不斷地進行尋路,當列車進站時,會選擇最近的車門上車,并跟隨列車一起移動[11]。
本文中使用的乘客模型是已經(jīng)綁定骨骼以及動畫的預制體(Prefab)。Prefab是Unity中的一種資源類型,存儲在項目資源中的一種可重復使用的對象,當預制體被添加到場景中,就創(chuàng)建了他的一個實例。將需要頻繁創(chuàng)建的物體設置為預制體可以節(jié)省內(nèi)存,乘客模型很適合被設置為預制體。
車廂門有左右的區(qū)別,乘客也根據(jù)左右分為2組控制,定義2個方法用于將模型預制體生成為實例并置于車廂內(nèi)。
通過為人物進行腳本編輯來實現(xiàn)人物的上下車。
本文以南京有軌電車麒麟線為模型,通過3ds MAX 建模軟件完成對虛擬列車場景及人物三維模型的建立,虛擬了 2個基本動作(walk、stand)。在此基礎上,使用NavMesh與人物動畫狀態(tài)機的結(jié)合,完成了人物在車廂內(nèi)的移動,實現(xiàn)了乘客動作的三維動作仿真。同時為有軌電車模擬駕駛系統(tǒng)提供了部分車站乘客上下車的場景,具有一定的實用價值。