|
最近从军事仿真行业换成了数字孪生行业,所以就研究了一下当前GIS-UE4插件。本文主要讲一下SuperMap Scene SDK、ArcGIS Maps SDK、Cesium for Unreal三方插件的使用,以及鼠标平移、旋转、缩放实现。
SuperMap Scene SDK
首先说一下超图的插件。为什么说先说超图呢?因为超图的操作更加符合Gis操作,鼠标中键基于轴旋转。其次可在线添加图层。
下载地址SuperMap技术资源中心|为您提供全面的在线技术服务
从超图官网下载,这个最新版本可以关闭超图验证,之前的一些版本需要超图证书,当然你也可以选择UE4官方基础版本,只不过里面少了一些常见的gis功能。
使用方法
主要通过SuperMap Desktop生成缓存,本地直接加载对应的文件。在安装包里有操作的详细说明。
在UE4 4.27版本中打开会崩溃是因为UE自带的Pixel Streaming插进引起,直接在插件中关闭。
运行时界面
常用的功能
1、SuperMap Georeference 组件,可以将 UE 对象移动到指定经纬度、高度的位置。
SuperMap Georeference 组件中经纬度写的是double类型,所以直接在UE4蓝图中没法使用,将其中的Longitude、Latitude、Height改成float类型。
2、飞行定位功能。
CameraState* cameraState = new CameraState();
cameraState->SetUGCameraState(target.X, target.Y, target.Z, 0, 0, 0);
RealspaceView::GetSingleton()->GetSceneControl()->GetScene()->Fly(cameraState, 2000);
3、地理坐标到笛卡尔坐标,迪卡儿坐标求地理坐标。
//地理坐标到笛卡尔坐标,涉及地理原点计算
SuperMapSDK::UnrealEngine::Algorithm3D::MathEngine::SphericalToCartesian_GeoOrigin(target);
//迪卡儿坐标求地理坐标
FVector Scene::CartesianToSpherical_GeoOrigin(FVector vPos)
{
Vector3d vLocal = Vector3d(vPos.X, vPos.Y, vPos.Z);
vLocal += Vector3d(m_pCameraControl->m_vecWorldOrigin);
FRotator fRotator;
FTransform fTransform = FTransform(fRotator, vLocal.ToFVector());
Matrix4d matRot(fTransform.ToMatrixWithScale());
matRot = matRot * Georeference::GetECEFtoGeoreference().Invert();
FMatrix matfloatRot;
Matrix4d::ToFMatrix(matRot, matfloatRot);
fTransform.SetFromMatrix(matfloatRot);
vLocal = fTransform.GetLocation();
vLocal *= CM_TO_M;
// 地理坐标
Vector3d vLonLat3d;
_CartesianToSphericalD(vLocal.Y, vLocal.X, vLocal.Z, vLonLat3d.X, vLonLat3d.Y, vLonLat3d.Z);
return FVector(vLonLat3d.X, vLonLat3d.Y, vLonLat3d.Z);
}
4、图层材质设置。
5、获取鼠标当前点坐标。
//! \brief 获取鼠标对应的地位位置
bool GetWorldPositionByDepth(FVector vMouse, Vector3d& vWorldPosition);
其实这原理很简单,就是已经知道屏幕位置,怎么求这个屏幕位置对应的世界位置和方向。可惜目前SuperMap不支持UE4射线检测,不能直接射线检测在图层上的位置。不然也不会采用这样的方式获取坐标点。
// 获取视图矩阵
FViewMatrices viewMatrices;
viewMatrices.UpdateViewMatrix(FVector(0.0,0.0,0.0), rDirection_normal);
FMatrix viewMatrix = viewMatrices.GetViewMatrix();
FMatrix viewProjMatrix = viewMatrix * projectMatrix;
FMatrix invViewProjMatrix = viewProjMatrix.Inverse();
float fMouseX = xMouse;
float fMouseY = yMouse;
//先拿到屏幕坐标
float PixelX = FMath::TruncToFloat(fMouseX);
float PixelY = FMath::TruncToFloat(fMouseY);
//拿到坐标后把坐标映射到0-1范围
const float NormalizedX = (PixelX - 0) / ((float)nScreenWidth);
const float NormalizedY = (PixelY - 0) / ((float)nScreenHeight);
//将坐标映射到NDC空间[-1,1]
const float ScreenSpaceX = (NormalizedX - 0.5f) * 2.0f;
const float ScreenSpaceY = ((1.0f - NormalizedY) - 0.5f) * 2.0f;
//裁剪空间的点转为世界空间
FVector4 vPos(ScreenSpaceX, ScreenSpaceY, 1 - fDepth, 1.0);
vPos = invViewProjMatrix.TransformFVector4(vPos);
//向量除以W归一到世界的近剪裁面
vWorldPosition = Vector3d(vPos.X, vPos.Y, vPos.Z);
if (vPos.W != 0.0f)
{
vWorldPosition = Vector3d(vWorldPosition.X / vPos.W, vWorldPosition.Y / vPos.W, vWorldPosition.Z / vPos.W);
}
vWorldPosition += vCameraLocation;优缺点
优点:SuperMap Scene SDK 功能多多,更加符合国人操作。SuperMap Desktop缓存特别方便。同时支持球面与平面,以及本地与在线服务。最后结尾我会说一下这三个插件怎么本地开服务。
缺点:自己看源码,教程太少,bug太多。
Cesium for Unreal
Cesium应该说是更新比其它两款积极。Github上可以下最新版https://github.com/CesiumGS/cesium-unreal/
官网学习链接 Cesium for Unreal
cesium 目前来说,教程比较多,用的人也是最多的,常用的功能已经满足使用,cesium坐标系转换都写好了直接暴露给蓝图,不需要你从c++找。
Cesium矢量文件处理
Cesium for Unreal 官网上说目前不支持 KML、SHP、GeoJSON 和 CZML 等矢量数据格式。但是cesiumlab3支持shp面模型通过通用模型切片处理和shp点生成实例模型处理。
cesiumlab数据处理流程图
在处理shp线的时候可以生成面然后生成体。以这样的方式加载shp文件同时还可以显示shp属性字段。
蓝图获取模型属性
显示属性字段
启http服务的小工具
正常我会启用ArcGIS Server或者geoserver发布地图服务,在上面的视频教程里提供了启http服务的小工具。地址 https://www.npmjs.com/package/serve
不需要cesiumlab服务。下图可快速开启http服务。
npx serve安装
npx serve开启
ArcGIS Maps SDK
下载地址arcgis maps sdk for game engines
使用教程
官网链接ArcGIS Maps SDK for Unreal Engine
个人感觉ArcGIS是cesium 增强版,多了空间和数据分析,以及图层透明度设置。ArcGIS同样支持在线服务与本地加载,不过ArcMap生成的本地TPK 文件速度比不上超图和cesium。
生成tpk文件
加载本地文件
鼠标平移、旋转、缩放的实现
方法一、 SpringArm
最简单的方法就是通过SpringArm,伸长相机臂来控制距离从来看起来缩放,然后设置UsePawnControlRoation 为true。这样就可以旋转了。
方法二、数学计算
计算鼠标点击位置与当前位置为半径R,然后计算鼠标在平面上的位移。从而计算在球体上的转动。
绕球体转动计算
判断一个点是否在多边形内部
这是阿里笔试算法题。通常我们判断一个坐标是否在一个区域内,主要有以下几种方法:
(1)面积和判别法:判断目标点与多边形的每条边组成的三角形面积和是否等于该多边形,相等则在多边形内部。
(2)夹角和判别法:判断目标点与所有边的夹角和是否为360度,为360度则在多边形内部。
(3)引射线法:从目标点出发引一条射线,看这条射线和多边形所有边的交点数目。如果有奇数个交点,则说明在内部,如果有偶数个交点,则说明在外部。
常用PNPOLY算法
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++)
{
if (((verty>testy!= (verty[j]>testy))&&
(testx < (vertx[j]-vertx) *(testy-verty) /(verty[j]-verty) + vertx))
c = !c;
}
return c;
}具体算法图解: |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|