王曉年, 宋夢譞, 丁保青
(同濟大學(xué)a.電子與信息工程學(xué)院;b.計算機與信息技術(shù)國家級實驗教學(xué)示范中心,上海 201804)
三維場景建模的目的是獲取物理世界的計算機描述,以便在其中實現(xiàn)各種仿真、測試和數(shù)字孿生等工作[1-3]。
圖像的三維場景建模[4]方法。可分為:通過提取圖像特征,根據(jù)相機運動結(jié)構(gòu)獲取三維信息;通過雙目或深度相機直接得到場景的深度。這兩類方法都可根據(jù)同步定位和地圖構(gòu)建相關(guān)算法獲得更為準(zhǔn)確的重構(gòu)結(jié)果[5]。理想的圖像建模擁有很高的真實感,重構(gòu)三維結(jié)果和語義對象有鴻溝,當(dāng)定位系統(tǒng)有誤差時,所建構(gòu)的模型也存在偏差。
利用激光雷達生成的點云數(shù)據(jù)進行三維場景重建的方法。激光器根據(jù)激光束發(fā)射的角度以及發(fā)射、接收的時間差能夠得到周圍環(huán)境的三維坐標(biāo)[6-7]。所探測到的三維點集合構(gòu)成點云數(shù)據(jù),得到周圍場景的模型。該方式具有精度高、不受光照影響等優(yōu)點。缺點是激光器價格昂貴,且所得點云較圖像過于稀疏,此外得到的三維數(shù)據(jù)中缺少色彩信息。
利用CAD[8-9]進行建模的方法。可獲得需要建模場景的平面數(shù)據(jù),再結(jié)合建筑物的外形特征和高度信息來進行建模。CAD 能夠得到非常準(zhǔn)確的三維模型數(shù)據(jù)。數(shù)據(jù)的獲取和處理都具有很大的挑戰(zhàn),場景的規(guī)劃和建筑物以及裝飾的規(guī)劃屬于不同的部門,出于安全和知識產(chǎn)權(quán)的壁壘,通常難以獲取;如果對場景重新測量,那么測繪的工作量會非常大。
二維地理數(shù)據(jù)相較于三維模型數(shù)據(jù)更易獲取,使用二維地圖[10-11]信息實現(xiàn)三維場景的建模可大大降低建模的復(fù)雜度和周期。即可根據(jù)二維地圖上的建筑物、河流、樹木和道路等幾何信息,借助于高度信息和紋理信息自動實現(xiàn)三維建模工作,極大地提高建模效率。
本文將討論如何從二維地圖中導(dǎo)出數(shù)據(jù)以及各種對象的自動生成方法,為三維場景的建模提供新的思路,以降低建模工作量。相較于Carla[12]仿真環(huán)境,本文方法可更好地適應(yīng)地圖信息的修改。區(qū)別于商業(yè)軟件CityEngine[2]和SketchUp[13]的建模方法,本文基于Unity3D[3]平臺和C#語言,利用免費地圖軟件和開放平臺實現(xiàn)全自主、全自動的三維建模流程和方法。平臺的開放性可為學(xué)生或科研工作者提供實驗和仿真,所建模型可用于各種仿真環(huán)境,比如用于定位、用于規(guī)劃導(dǎo)航以及SLAM測試等。這一特點使得本文方法對新場景的構(gòu)建更方便簡潔,且對場景或者道路的動態(tài)變化更具適應(yīng)性。
OpenStreetMap[10,14]是一個免費提供全球電子地圖的網(wǎng)站,以拓?fù)浣Y(jié)構(gòu)組織地圖數(shù)據(jù)。數(shù)據(jù)中包括空間數(shù)據(jù)和屬性數(shù)據(jù)。空間數(shù)據(jù)有3 種,分別是結(jié)點(Node)、路徑(Way)和關(guān)系(Relation),Node 和Way用于表示地圖中的點、線數(shù)據(jù);Way 是一個有序的Node序列,如果該序列首尾Node 相同,則表示區(qū)域,反之則對應(yīng)的是線段。Relation 把多個Node 和Way組織起來表示復(fù)雜的圖形。文中根據(jù)地圖數(shù)據(jù)構(gòu)造了MapNode類和MapWay 2 個類,用以組織所有的Node和Way,部分變量定義如下:
public class MapNode
{
public long id;
public double longitude,latitude;
public float x,y;
public Dictionary <string,string >tags;
public List <MapWay >ways;
……
};
MapNode類中的成員變量包括節(jié)點的id 值;結(jié)點的經(jīng)緯度坐標(biāo)longitude、latitude;結(jié)點的二維坐標(biāo)x、y;結(jié)點的標(biāo)簽值tags 和包括此節(jié)點的路徑的id 值的列表ways。
public class MapWay
{
public long id;
public List <long >nodeIds;
public List <MapNode >nodes;
public Dictionary <string,string >tags;
public List <MapWay >leadTos;
……
}
MapWay中的成員變量包括路徑的id 值;該路徑所包括結(jié)點的id值列表nodeIds;該路徑所包括結(jié)點的列表nodes;路徑的標(biāo)簽值tags以及與該路徑相連接的下一條路徑的列表leadTos。
讀取選定區(qū)域的地圖數(shù)據(jù),構(gòu)建一個以MapWay為數(shù)據(jù)類型的列表MapWayList,便于后續(xù)對象的遍歷和查找。MapWayList可以通過成員變量nodes訪問該路徑上的所有MapNode類型的節(jié)點。
游戲?qū)ο笫荱nity3D[11,15]中的基本載體,一個游戲?qū)ο笊峡梢栽黾佣鄠€組件,其中比較基礎(chǔ)的包括Transform、Mesh Filter 和Mesh Renderer 等組件,這些組件共同決定了物體呈現(xiàn)在虛擬場景中的樣子。Transform決定了物體在游戲界面中的位姿和尺度。Mesh Filter 決定展現(xiàn)哪一個Mesh。Mesh Renderer 決定以何種方式渲染Mesh,包括使用哪種材質(zhì)球、是否接受陰影和投影等,二者共同決定了物體的表現(xiàn)形式。Mesh至少包括頂點坐標(biāo)的集合以及三角形頂點索引序列。由于MapWayList 中都是區(qū)域或者路徑的屬性描述,在渲染前必須得到對象的Mesh 數(shù)據(jù),耳切法就是把多邊形分解為三角形的經(jīng)典方法[9]。
耳切法的基本思想是找出多邊形的耳朵點,將其從頂點序列中移除。當(dāng)最后多邊形的頂點序列中只剩下3 個頂點時,分解完成。圖1 中的陰影部分即為一個耳朵,其對應(yīng)頂點0 即為一個耳朵點。

圖1 多邊形的耳朵示例
為得到更合理的切分結(jié)果,在耳切法的基礎(chǔ)上進行了如下處理:
(1)頂點序列預(yù)處理。Unity3D 中三角形頂點的索引順序會影響三角形呈現(xiàn)的方向。使用矢量叉乘的方法判斷多邊形頂點順序。先計算相鄰的3 個頂點構(gòu)成2 個矢量,2 個矢量叉乘結(jié)果的正、負(fù)代表序列點所指的方向,當(dāng)叉乘結(jié)果為正時,采用順時針方向的頂點存儲方式;反之,對整個頂點索引序列逆序處理。
(2)凸點的確定。在分割三角形時,耳朵點應(yīng)從凸點中選擇。判斷凸點的方法也采用叉乘檢測法,即定義凸點為相鄰3 個點構(gòu)成2 個矢量叉乘的方向為正的點。
(3)耳朵點移除順序的原則。如果移除耳朵點的順序選取不當(dāng),會導(dǎo)致多邊形的分割不合理,如圖2(a)所示。耳朵點采用逐層刪除原則,首先移除頂點的內(nèi)角接近90°的點;如果有多個候選解時,優(yōu)先移除可能構(gòu)成三角形內(nèi)角方差較小的那個頂點。同樣圖形,本文的分割結(jié)果如圖2(b)所示。

圖2 移除耳朵點不同順序?qū)Χ噙呅畏指畹挠绊?/p>
地圖中的元素,包括道路,河流和建筑等都用首尾相接的點和其他屬性描述。首尾相接的點構(gòu)成一個多邊形區(qū)域,通過上述耳切法可得三角形分割結(jié)果,實現(xiàn)紋理的貼圖。
建筑物是典型的三維物體,只有對每個墻面進行渲染,才能展現(xiàn)出逼真的三維效果。遍歷MapWayList,如果tags包括“building”則表示物體為一幢建筑。建筑物高度由建筑物的層數(shù)和層高共同決定。其中層數(shù)可從地圖中建筑的標(biāo)簽讀出。對于缺失此數(shù)據(jù)的建筑,如果沒有人為設(shè)定則賦予隨機值,表現(xiàn)為某些建筑物的高度在每一次建模中都會不同。層高則預(yù)先設(shè)定為固定值。
建筑物的頂面形狀就是地圖中的封閉區(qū)域,由按照逆時針順序存儲的頂點構(gòu)成;每個面墻則通過給邊加上高度后形成。墻面部分直接影響重建的視覺效果,由于建筑物每個面形狀和高度各異,給貼圖帶來一些挑戰(zhàn)。表面貼圖的素材和實際場景越接近,構(gòu)建的三維場景越真實,真實的貼圖需要采集和標(biāo)定建筑物不同角度的照片。為讓虛擬建筑物看起來更具多樣性,建筑物的表面采用多種圖片構(gòu)成的紋理庫作為素材。貼圖時遵循如下兩個原則:
(1)宏觀和微觀紋理并存。將圖片中重復(fù)出現(xiàn)的部分視作一個微觀紋理單元,如圖3 中紅色方框部分所示,該單元對應(yīng)一層樓的高度和一扇窗戶的寬度。為提高效率,同時保存宏觀單元,如圖3 中整體紋理所示。貼圖時,可使用多個微觀單元鋪滿整個墻面,則貼滿如圖所示墻面需要貼圖10 ×5 次,而宏觀單元僅需一次。

圖3 貼圖實例
(2)自動匹配加人為指定。用戶可指定某個墻面使用的紋理序號,否則程序自動從墻面紋理圖庫中尋找最適合的紋理圖片,選擇次序如下:首先根據(jù)建筑物層數(shù)和宏觀紋理中的層數(shù)做最優(yōu)匹配,當(dāng)存在多個選擇時優(yōu)先選擇寬度更匹配的紋理,如果依然有多個候選紋理則由程序隨機決定。貼圖時對于不能完全覆蓋的情形,則在宏觀紋理圖像適度變形的前提下用微觀紋理進行補充。
地圖文件中沒有地形數(shù)據(jù),但當(dāng)tags 包括“natural”并且標(biāo)簽的value 值為“water”時,表示此物體為一條河流;當(dāng)標(biāo)簽包含“l(fā)anduse”且該標(biāo)簽value值為“grass”時,此數(shù)據(jù)為一片綠地。
道路是相對標(biāo)準(zhǔn)區(qū)域,正常道路可根據(jù)車道數(shù)、屬性以及道路寬度動態(tài)實現(xiàn)貼圖。對特殊區(qū)域,比如Y型路口或者環(huán)島等可先三角化然后再貼圖。地圖中沒有指示草地和河流的高度,需要在生成平面的基礎(chǔ)上根據(jù)屬性進行調(diào)整。通過將降低位于河流內(nèi)頂點的高度,形成下陷的地形。類似,也可抬高草地區(qū)域內(nèi)每個頂點的高度形成草地。通過這種方法得到河床的地面如圖4(a)所示。如果現(xiàn)實中的河床比較平緩,可將所有頂點坐標(biāo)進行拉普拉斯平滑處理,經(jīng)過平滑處理后的河床如圖4(b)所示。

圖4 有河床的地形網(wǎng)格
草地的貼圖方法與河流相同。通過法線貼圖,使物體表面呈凹凸不平的逼真效果,貼圖后的河流和草地如圖5 所示。
地圖上沒有標(biāo)記的交通燈,可人為修改地圖。程序也可在道路的交叉處加上偏移后設(shè)定交通燈位置。對于三維環(huán)境重構(gòu)而言,道路兩旁的行道樹是必不可少的部分。行道樹在地圖中沒有標(biāo)記,人為添加工作量太大。采取如下方法:遍歷MapWayList中的每條數(shù)據(jù),當(dāng)某條數(shù)據(jù)的標(biāo)簽包含“highway”且該標(biāo)簽的value值為“service”時,即對應(yīng)一條道路,根據(jù)道路的數(shù)據(jù)便可進行樹木模型的擺放。
行道樹設(shè)定算法的原則:
(1)同一條id的道路選用一種樹形。
(2)車行道一般會有2 個方向,如將每條路的兩側(cè)均放置行道樹,會造成2 條路中間樹木的重疊和冗余,在本文中只在道路前進方向的右側(cè)放置行道樹。
(3)行道樹之間的間隔可改變,可人為設(shè)定。
用上述方法為每條道路計算出行道樹的位置,隨機從多個樹木素材中選出一種放置選取的樹木即完成行道樹的擺放。一條道路的路面紋理和行道樹放置后如圖6 所示。

圖6 路面和行道樹
從OpenStreetMap網(wǎng)站導(dǎo)出某校區(qū)公開的地圖文件,各圖層合并后如圖7 所示。用文中方法自動構(gòu)建的部分三維場景如圖8 所示。

圖7 某校區(qū)公開地圖

圖8 自動建模的部分場景
本文自動建模的方法可即刻根據(jù)OpenStreetMap數(shù)據(jù)構(gòu)建三維場景,并在更換OpenStreetMap數(shù)據(jù)為其他地區(qū)后仍然適用。此方法為測試系統(tǒng)進行場景建模可達到快速適應(yīng)場景變換的效果,也可據(jù)此動態(tài)紋理環(huán)境實現(xiàn)豐富的數(shù)據(jù)信息生成等。所自動構(gòu)建的三維場景被大學(xué)生綜合設(shè)計與實踐選為基礎(chǔ)平臺使用,基于此實現(xiàn)模擬“滴滴”叫車服務(wù),完成路徑規(guī)劃以及實驗仿真。后續(xù)工作中可加入更多智能非玩家角色,使得構(gòu)建環(huán)境具備更廣泛的應(yīng)用場景。