基于UE4/Unity绘制地图 - 肯定展现区域

前言

基于UE4/Unity绘制地图基础元素-线html

基于UE4/Unity绘制地图基础元素-面和体java

基础知识

在研究清楚如何绘制地图的线面体以后,接下来须要肯定须要展现的地图区域了。程序员

地图能够当作是一个巨型的开放世界游戏场景,所以为了便于数据存储和查找,传统的作法是将地球根据墨卡托投影转换为平面地图,再将地图分级分块进行切片,经过索引获取到对应的数据。web

image.png

以OSM的地图为例,导出数据是以当前视口的大小,查询对应级别的切片获得的。Google的卫星图、地形图等也都是按照分级分块的规则进行管理。算法

image.png

基于视口展现

传统的地图展现方式,展现区域的肯定一般是与视口绑定的,即地图切片只加载摄像机视锥体与地图所在平面相交的部分,并在摄像机移动时动态进行切片的更替。数组

image.png

这种方式对于查看全世界全量地图数据的场景很是合适,但对于但愿使用游戏引擎构建一个更精细的世界来讲,有一些不足:异步

  • 视锥体动态计算切片的前提是,必定要保证其与地图所在平面必定有四个交点,所以摄像机的FOV(竖直方向的张开角度)不能太大,不然当摄像机俯仰角变化时,视锥体的上下两个面可能与地图所在平面平行,从而致使没法计算切片。
  • 在平行以前,一样也会由于角度问题,致使计算获得的切片数量过大,没法进行加载;或由于设置了一些切片数量的限制,致使看到的世界有所缺失。

所以视椎体动态计算的方式,一般会固定一个较小的FOV,而且限制俯仰角。同时由于性能的限制,对于大俯仰角的状况,经过一些手段进行切片的数量优化。以腾讯的JS API GL为例,为了减小大俯仰角形成切片数量过大带来的性能瓶颈,采用雾化的方式将较远处的场景进行剔除,使得能够无缝衔接查看整个世界。ide

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

所以顺着这个思路,借助于光栅化的方式求切片集合:

一、光栅化的基本单位是三角形,所以对于行政区划的多边形,先调用三角剖分算法分解为三角形的集合。 二、对于一个三角形,最经典的方式就是拆为两个更容易绘制的三角形,一个底边平行,一个顶边平行,再使用水平扫线法求得全部的切片。

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

来源:知乎

著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。

相关文章
相关标签/搜索