前言
基礎知識
在研究清楚如何繪製地圖的線面體以後,接下來須要肯定須要展現的地圖區域了。程序員
地圖能夠當作是一個巨型的開放世界遊戲場景,所以爲了便於數據存儲和查找,傳統的作法是將地球根據墨卡託投影轉換爲平面地圖,再將地圖分級分塊進行切片,經過索引獲取到對應的數據。web
以OSM的地圖爲例,導出數據是以當前視口的大小,查詢對應級別的切片獲得的。Google的衛星圖、地形圖等也都是按照分級分塊的規則進行管理。算法
基於視口展現
傳統的地圖展現方式,展現區域的肯定一般是與視口綁定的,即地圖切片只加載攝像機視錐體與地圖所在平面相交的部分,並在攝像機移動時動態進行切片的更替。數組
這種方式對於查看全世界全量地圖數據的場景很是合適,但對於但願使用遊戲引擎構建一個更精細的世界來講,有一些不足:異步
- 視錐體動態計算切片的前提是,必定要保證其與地圖所在平面必定有四個交點,所以攝像機的FOV(豎直方向的張開角度)不能太大,不然當攝像機俯仰角變化時,視錐體的上下兩個面可能與地圖所在平面平行,從而致使沒法計算切片。
- 在平行以前,一樣也會由於角度問題,致使計算獲得的切片數量過大,沒法進行加載;或由於設置了一些切片數量的限制,致使看到的世界有所缺失。
所以視椎體動態計算的方式,一般會固定一個較小的FOV,而且限制俯仰角。同時由於性能的限制,對於大俯仰角的狀況,經過一些手段進行切片的數量優化。以騰訊的JS API GL爲例,爲了減小大俯仰角形成切片數量過大帶來的性能瓶頸,採用霧化的方式將較遠處的場景進行剔除,使得能夠無縫銜接查看整個世界。ide
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)值。同時,地圖所在平面也可使用一個方程表示,所以,視錐體與地圖的一個交點就是三個平面的相交點。(以左上交點爲例,將視椎體的左、上平面方程與地圖所在平面方程聯立,便可獲得交點)學習
其中的聯立求交,可使用矩陣運算快速求得:
若聯立有解,則矩陣可逆,那麼行列式不爲0能夠做爲判斷有解的快速驗證方式。當肯定有解後,則可以使用逆矩陣快速求解:
基於行政區劃展現
基於視口展現方案理論上徹底可行,但對於有高性能顯卡支撐的遊戲引擎來講遠遠不夠:
- 地圖至少要像GTA那樣,目之所及都有元素,不能將遠裁剪面如此提早。
- 攝像機須要自由度,能夠爲所欲爲的進行移動。
所以,比較直接的想法是,若是想展現一個城市,那就一次性渲染出城市的全部數據。
城市的數據能夠藉助於現有的服務獲取,以騰訊位置服務的WebService API爲例,能夠經過行政區劃服務獲取到對應的行政區劃點串信息,依託於地圖數據的切片存儲形式,所以只須要肯定這個行政區劃點串覆蓋的切片集合就能夠了。
// 行政區劃線點串以連續的經緯度進行表示 "polygon": [ [116.809403,39.61482,116.790175,39.610555,116.780286,39.593196....],]
根據基礎知識所說,每個切片都是一個小正方形,而行政區劃點串信息表明的是一個大多邊形,所以轉化爲使用小正方形切片去近似一個多邊形的問題。
是否是聽起來十分像光柵化。
所以順着這個思路,藉助於光柵化的方式求切片集合:
一、光柵化的基本單位是三角形,所以對於行政區劃的多邊形,先調用三角剖分算法分解爲三角形的集合。 二、對於一個三角形,最經典的方式就是拆爲兩個更容易繪製的三角形,一個底邊平行,一個頂邊平行,再使用水平掃線法求得全部的切片。
具體算法能夠參考這篇TriangleRasterization的文章,其中還有Bresenham算法和重心座標算法等其餘光柵化的算法。
獲取到全部切片數據後,就能夠進行行政區劃的展現了。
基於位置的動態展現方法
藉助於光柵化算法能夠獲得切片集合進行渲染展現,但基於行政區劃的方式展現也有弊端,即CPU/GPU資源有限,對於幾千平方千米的城市可能沒法粗暴的直接支持。
和開放大世界遊戲同樣,比較合理的方式就是隨着當前位置動態載入/載出場景,使得感官上構建出一個無縫銜接的大世界。
以UE4爲例,Epic提供了World Composition這個利器去支持遊戲開發者製做開發大世界遊戲,開發者能夠方便的並行編輯每一個子關卡。運行時根據遊戲角色所在的位置,能夠異步加載/卸載子關卡,達到無縫銜接的效果。
而對於不適合使用World Composition的場景,能夠退一步使用Level Streaming去進行手動管理,初步的使用方法,能夠參考以前的文章,對於Level Streaming的一些初步的學習。
基於位置的動態展現方法須要作更多的額外工做去達到完美的沉浸效果,目前這部分依舊還在摸索中,但願有朝一日能夠徹底解決。這篇文章權當是拋磚引玉,但願給你們帶來一些思考。
做者:程序員阿Tu
連接:https://zhuanlan.zhihu.com/p/353203619
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。