基於UE4/Unity繪製地圖 - 確定展示區域

前言

基於UE4/Unity繪製地圖基礎元素-線

基於UE4/Unity繪製地圖基礎元素-面和體

基礎知識

在研究清楚如何繪製地圖的線面體之後,接下來需要確定需要展示的地圖區域了。

地圖可以看成是一個巨型的開放世界遊戲場景,因此爲了便於數據存儲和查找,傳統的做法是將地球根據墨卡託投影轉換爲平面地圖,再將地圖分級分塊進行切片,通過索引獲取到對應的數據。

image.png

以OSM的地圖爲例,導出數據是以當前視口的大小,查詢對應級別的切片得到的。Google的衛星圖、地形圖等也都是按照分級分塊的規則進行管理。

image.png

基於視口展示

傳統的地圖展示方式,展示區域的確定通常是與視口綁定的,即地圖切片只加載攝像機視錐體與地圖所在平面相交的部分,並在攝像機移動時動態進行切片的更替。

image.png

這種方式對於查看全世界全量地圖數據的場景非常合適,但對於希望使用遊戲引擎構建一個更精細的世界來說,有一些不足:

  • 視錐體動態計算切片的前提是,一定要保證其與地圖所在平面一定有四個交點,因此攝像機的FOV(豎直方向的張開角度)不能太大,否則當攝像機俯仰角變化時,視錐體的上下兩個面可能與地圖所在平面平行,從而導致無法計算切片。
  • 在平行之前,同樣也會因爲角度問題,導致計算得到的切片數量過大,無法進行加載;或因爲設置了一些切片數量的限制,導致看到的世界有所缺失。

因此視椎體動態計算的方式,通常會固定一個較小的FOV,並且限制俯仰角。同時因爲性能的限制,對於大俯仰角的情況,通過一些手段進行切片的數量優化。以騰訊的JS API GL爲例,爲了減少大俯仰角造成切片數量過大帶來的性能瓶頸,採用霧化的方式將較遠處的場景進行剔除,使得可以無縫銜接查看整個世界。

image.png

UE4和Unity都有能夠獲得視椎體的接口。以UE4爲例,ULocalPlayer中存儲了Viewport相關的信息,根據矩陣變換的信息可以得到存儲視椎體信息的FConvexVolume。

ULocalPlayer* LocalPlayer = GetWorld()->GetFirstPlayerController()->GetLocalPlayer();

FSceneViewProjectionData ProjectionData;

LocalPlayer->GetProjectionData(LocalPlayer->ViewportClient->Viewport, eSSP_FULL, ProjectionData);
    
FMatrix ViewProjectionMatrix = ProjectionData.ComputeViewProjectionMatrix();
    
FConvexVolume ViewFrustum;
    
GetViewFrustumBounds(ViewFrustum, ViewProjectionMatrix, true);

FConvexVolume的Planes數組中依次存儲了左右上下四個平面的方程FPlane,比較特殊的是FPlane是以Xx+Yy+Zz=W的形式存儲了(X,Y,Z,W)值。同時,地圖所在平面也可以使用一個方程表示,因此,視錐體與地圖的一個交點就是三個平面的相交點。(以左上交點爲例,將視椎體的左、上平面方程與地圖所在平面方程聯立,即可得到交點)

其中的聯立求交,可以使用矩陣運算快速求得:

image.png

若聯立有解,則矩陣可逆,那麼行列式不爲0可以作爲判斷有解的快速驗證方式。當確定有解後,則可使用逆矩陣快速求解:

image.png

基於行政區劃展示

基於視口展示方案理論上完全可行,但對於有高性能顯卡支撐的遊戲引擎來說遠遠不夠:

  • 地圖至少要像GTA那樣,目之所及都有元素,不能將遠裁剪面如此提前。
  • 攝像機需要自由度,可以隨心所欲的進行移動。

因此,比較直接的想法是,如果想展示一個城市,那就一次性渲染出城市的所有數據。

image.png

城市的數據可以藉助於現有的服務獲取,以騰訊位置服務的WebService API爲例,可以通過行政區劃服務獲取到對應的行政區劃點串信息,依託於地圖數據的切片存儲形式,因此只需要確定這個行政區劃點串覆蓋的切片集合就可以了。

// 行政區劃線點串以連續的經緯度進行表示
"polygon": [ [116.809403,39.61482,116.790175,39.610555,116.780286,39.593196....],]

根據基礎知識所說,每一個切片都是一個小正方形,而行政區劃點串信息代表的是一個大多邊形,因此轉化爲使用小正方形切片去近似一個多邊形的問題。

是不是聽起來十分像光柵化

image.png

因此順着這個思路,藉助於光柵化的方式求切片集合:

1、光柵化的基本單位是三角形,因此對於行政區劃的多邊形,先調用三角剖分算法分解爲三角形的集合。 2、對於一個三角形,最經典的方式就是拆爲兩個更容易繪製的三角形,一個底邊平行,一個頂邊平行,再使用水平掃線法求得所有的切片。

image.png

具體算法可以參考這篇TriangleRasterization的文章,其中還有Bresenham算法和重心座標算法等其他光柵化的算法。

獲取到所有切片數據後,就可以進行行政區劃的展示了。

基於位置的動態展示方法

藉助於光柵化算法可以得到切片集合進行渲染展示,但基於行政區劃的方式展示也有弊端,即CPU/GPU資源有限,對於幾千平方公里的城市可能無法粗暴的直接支持。

和開放大世界遊戲一樣,比較合理的方式就是隨着當前位置動態載入/載出場景,使得感官上構建出一個無縫銜接的大世界。

以UE4爲例,Epic提供了World Composition這個利器去支持遊戲開發者製作開發大世界遊戲,開發者可以方便的並行編輯每個子關卡。運行時根據遊戲角色所在的位置,可以異步加載/卸載子關卡,達到無縫銜接的效果。

image.png

而對於不適合使用World Composition的場景,可以退一步使用Level Streaming去進行手動管理,初步的使用方法,可以參考之前的文章,對於Level Streaming的一些初步的學習

基於位置的動態展示方法需要做更多的額外工作去達到完美的沉浸效果,目前這部分依舊還在摸索中,希望有朝一日可以完全解決。這篇文章權當是拋磚引玉,希望給大家帶來一些思考。

作者:程序員阿Tu

鏈接:https://zhuanlan.zhihu.com/p/353203619

來源:知乎

著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章