注:正常在WEB上显示三维地形首选Cesium,本文内容仅作为研究,展示文章用DEM制作通用三维地形模型中制作的局部三维地形模型

Cesium是可以很容易的实现在WEB端三维地形的,下面的图是分别是使用基于Cesium的Mars3D和超图的iClient3D出来的效果。不过Cesium终究是基于地球的,比较适合大块区域的展示。和文章用DEM制作通用三维地形模型里做的模型效果来比,还是差点意思,资源占用也很高。加上因为三维模型都是笛卡尔坐标系,我们在制作模型的时候也使用了高斯克吕格投影坐标系,直接整个模型加到球形的Cesium里再缩放到一个县的范围那么大,必然是不能处处对应准的,所以那篇文章的成果就不太适合用Cesium展示了。

理论上只要支持gltf的webgl库比如three.js等都是可以展示我再上篇文章中生成的地形模型的,我使用的babylon.js,我在之前文章蓝牙Beacon室内定位全栈里有用过,功能比较强大,可以说是一个WebGL的三维引擎也不为过。

babylon.js的使用比较方便,引入babylon.js和加载gltf的babylonjs.loaders.js,使用canvas进行渲染。

<!DOCTYPE html>
<html><head><meta charset="utf-8"><meta name="description" content=""><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><title>三维地形</title><link rel="stylesheet" media="all" href="./css/index.css"><script src="./lib/babylon/babylon.js"></script><script src="./lib/babylon/loaders/babylonjs.loaders.js"></script></head><body><canvas id="renderCanvas"></canvas></body><script src="./js/projection.js"></script><script src="./js/index.js"></script>
</html>

首先初始化引擎和场景

let _canvas,_engine,_scene,_camera;_canvas = document.getElementById('renderCanvas');
_engine = new BABYLON.Engine(_canvas, true);
_scene = createScene();
_engine.runRenderLoop(function() {if (_scene.activeCamera) {_scene.render();}
});//创建场景const createScene = function() {const scene = new BABYLON.Scene(_engine);_camera = new BABYLON.ArcRotateCamera('camera', Math.PI/2, Math.PI/4, 30, new BABYLON.Vector3(0, 0, 0));_camera.inputs.attached.mousewheel.wheelPrecision = 8;_camera.inputs.attached.pointers.panningSensibility = 250;_camera.inputs.attached.pointers.angularSensibilityX = 5000;_camera.inputs.attached.pointers.angularSensibilityY = 5000;_camera.attachControl(_canvas, true);const light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0));return scene;
}

在创建引擎和场景的时候,为了方便调试,可以在场景中把坐标轴展示出来,很可惜babylon.js不原生支持坐标轴展示,需要手动画上去。

//创建坐标轴
const showAxis = function (size) {const makeTextPlane = function (text, color, size) {const dynamicTexture = new BABYLON.DynamicTexture('DynamicTexture', 50, _scene, true);dynamicTexture.hasAlpha = true;dynamicTexture.drawText(text, 5, 40, 'bold 36px Arial', color, 'transparent', true);const plane = new BABYLON.Mesh.CreatePlane('TextPlane', size, _scene, true);plane.material = new BABYLON.StandardMaterial('TextPlaneMaterial', _scene);plane.material.backFaceCulling = false;plane.material.specularColor = new BABYLON.Color3(0, 0, 0);plane.material.diffuseTexture = dynamicTexture;return plane;}; const axisX = BABYLON.Mesh.CreateLines('axisX', [new BABYLON.Vector3.Zero(), new BABYLON.Vector3(size, 0, 0), new BABYLON.Vector3(size * 0.95, 0.05 * size, 0),new BABYLON.Vector3(size, 0, 0), new BABYLON.Vector3(size * 0.95, -0.05 * size, 0)], _scene);axisX.color = new BABYLON.Color3(1, 0, 0);const xChar = makeTextPlane('X', 'red', size / 10);xChar.position = new BABYLON.Vector3(0.9 * size, -0.05 * size, 0);const axisY = BABYLON.Mesh.CreateLines('axisY', [new BABYLON.Vector3.Zero(), new BABYLON.Vector3(0, size, 0), new BABYLON.Vector3(-0.05 * size, size * 0.95, 0),new BABYLON.Vector3(0, size, 0), new BABYLON.Vector3(0.05 * size, size * 0.95, 0)], _scene);axisY.color = new BABYLON.Color3(0, 1, 0);const yChar = makeTextPlane('Y', 'green', size / 10);yChar.position = new BABYLON.Vector3(0, 0.9 * size, -0.05 * size);const axisZ = BABYLON.Mesh.CreateLines('axisZ', [new BABYLON.Vector3.Zero(), new BABYLON.Vector3(0, 0, size), new BABYLON.Vector3(0, -0.05 * size, size * 0.95),new BABYLON.Vector3(0, 0, size), new BABYLON.Vector3(0, 0.05 * size, size * 0.95)], _scene);axisZ.color = new BABYLON.Color3(0, 0, 1);const zChar = makeTextPlane('Z', 'blue', size / 10);zChar.position = new BABYLON.Vector3(0, 0.05 * size, 0.9 * size);};

加载DEM glb文件

//加载DEM
BABYLON.SceneLoader.LoadAssetContainer('./','asset/dem.glb' , _scene, function (container) {container.meshes[0].id = '__dem__';container.meshes[0].name = '__dem__';container.addAllToScene();
});

毕竟这是一个地理数据,难免需要加一些其他地理数据,因此需要实现坐标转换。这里需要再次说明,之前所有的数据制作流程都是使用的高斯克吕格投影投影,为什么要是用高斯克吕格投影请看我的文章三维GIS建模不要用墨卡托投影,高斯克吕格投影投影和经纬度之间的坐标转换请看我的文章蓝牙Beacon室内定位全栈的移动端展示模型部分。单就我这个DEMO来说,还有一点点不同,我使用的坐标系是CGCS2000_3_Degree_GK_Zone_37而不是CGCS2000_3_Degree_GK_CM_111E(两者有啥区别以及为什么会有两种以后有机会再说),加上我们建模的时候不是直接按图像的尺寸来的,有一个缩放,因此在经纬度转成高斯克吕格投影坐标系之后,还需要做一个转换到当前的三维空间坐标,代码如下:

//经纬度转场景坐标
const LngLat2XY = function(lng,lat)
{const prjPosition = _projection.LngLat2XY(lng,lat);const dx = (prjPosition[0] + 37500000) - _center[0];const dy = prjPosition[1] - _center[1];const x = dx/_cellSize/100;const y = dy/_cellSize/100;return [-x,-y]}

其中_center_cellSize从DEM影像数据的属性信息来。

然后我们就可以按位置加入一些模型了,比如

//加载模型BABYLON.SceneLoader.LoadAssetContainer('./','asset/camera.glb' , _scene, function (container) {container.meshes[0].id = 'camera_1';container.meshes[0].name = 'camera_1';container.meshes[0].scaling = new BABYLON.Vector3(15, 15, 15);const xy = LngLat2XY(111.288,30.485)container.meshes[0].position = new BABYLON.Vector3(xy[0], 2, xy[1]);container.addAllToScene();const points = [new BABYLON.Vector3(xy[0], -0.5, xy[1]),new BABYLON.Vector3(xy[0], 2, xy[1])];//位置点虚线const line = BABYLON.MeshBuilder.CreateDashedLines("camera_line", {points: points,dashSize: 50,gapSize: 25,dashNb: 10});line.color = new BABYLON.Color3(0, 0, 1);
});

还可以在上面加Geojson数据,但是我没找到怎么让线贴着地形走的方式。

    const request = new XMLHttpRequest();request.open('get','./asset/XZQ.geojson');request.send();request.onload = ()=>{if (request.status == 200) {const features = JSON.parse(request.responseText).featuresfeatures.forEach(feature => {const coords = feature.geometry.coordinates[0][0]const positons = []for (let index = 0; index < coords.length; index++) {const coord = coords[index];const xy = LngLat2XY(coord[0],coord[1])positons.push(new BABYLON.Vector3(xy[0], 0.5, xy[1]))}const xzqLine = BABYLON.MeshBuilder.CreateLines(`xzqLine_${feature.properties.XZQDM}`, {points: positons});xzqLine.color = new BABYLON.Color3(1, 1, 1);});}}

我想,既然画上去的线没法贴地,那我可不可以给模型贴材质贴图呢。于是,我把要在上面展示的数据转换坐标系到CGCS2000_3_Degree_GK_Zone_37,通过GeoServer发布成WMS服务,将通过WMS请求回来的图片当做材质贴图贴在模型上。代码如下:

 const url = `${_geoserverUrl}/map/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&FORMAT=image/png&TRANSPARENT=true&STYLES&LAYERS=map:xzq&SRS=EPSG:4525&WIDTH=${_imgSize[0]}&HEIGHT=${_imgSize[1]}&BBOX=${xmin},${ymin},${xmax},${ymax}`
let orgMat = container.meshes[1].material;
orgMat.bumpTexture = new BABYLON.Texture(url, _scene);
orgMat.bumpTexture.vScale = -1

这里需要注意,请求里的WIDTH和HEIGHT要和建模时使用的图片成比例,我是直接使用的原尺寸。请求里面的BBOX的最大值最小值一定要是用DEM影像属性里的范围,不能错。SRS要是用对应的高斯克吕格坐标系,也不能错。

最终效果就如图了。

WEB端显示三维地形模型相关推荐

  1. 利用ros3d.js实现 turtlebot3 在web 端显示并导航

    ros3d导航,rosweb, 利用ros3djs实现 turtlebot3 在web 端显示并导航 主要是用到 ros3djs.rosbridge_server.tf2_web_republishe ...

  2. 使用海康威视设备在Web端显示实时视频

    前言 目前做的项目,需要Web端显示实时视频数据.本次项目使用的是海康威视的摄像头进行实时监控. 硬件:萤石的摄像头(海康威视旗下的),海康威视的硬盘录像机. 软件:vlc 2.2.6版本. Web端 ...

  3. 海康威视设备在Web端显示实时(回放)视频

    前言 目前做的项目,需要Web端显示实时视频数据.本次项目使用的是海康威视的摄像头进行实时监控. 硬件:海康威视的摄像头 软件:video.js.nginx.vlc 参考:https://blog.c ...

  4. zabbix搭建完,web端显示“zabbix服务器端运行中 不”

    zabbix搭建完,web端显示"zabbix服务器端运行中 不"如下图: 但是查看服务器的状态是running 然后查日志/var/log/zabbix/zabbix-serve ...

  5. 见证一张CAD图如何蜕变成一个高大上的三维地形模型(一)

    一般情况: 数据准备1.dem栅格图一张,2.对应dem位置的影像图一张即可 软件准备:ArcScene(esri arcgis 的是一个三维扩展模块,版本:10以上,本文10.2)或者terraBu ...

  6. 利用ros3djs接收pointcloud2在web端显示

    因项目需要,要将道路实时的点云流在经过算法处理后在web端显示出来.其中用到点云检测算法,然后发布相应的处理后的点云topic.在web端相应位置创建3Dview接收显示. 主要是用到 ros3djs ...

  7. CAD网页Web端显示开发为什么要以WebGIS的思路来开发?

    背景 在之前的博文CAD图DWG解析WebGIS可视化技术分析总结中讲解了如何把CAD的DWG格式的图纸Web可视化的方案.博文发布后,受到不少同行们的关注,也有不少咨询一些专业问题,其中大家可能疑惑 ...

  8. 如何使用SU生成三维地形模型

    Sketchup是一套直接面向设计方案创作过程的设计工具,其创作过程能够充分表达设计师的思想而且完全满足与客户即时交流的需要,经常会用到Sketchup快速表现景观设计方案,景观中会涉及到缓坡草地.生 ...

  9. MicroStation里CASS地形数据生成三维地形模型

    将如下CASS地形数据文件稍作编辑,生成MicroStation输入命令脚本: place point; xy=362047.09,3254845.853,88.288; xy=362047.273, ...

最新文章

  1. 技术图文:Python的属性装饰器详解
  2. php case语句 分号
  3. Zabbix4.2对IIS监控摸索记录
  4. 【转载】变量的存储类别
  5. 阿里腾讯今日头条纷纷选择的工具,ClickHouse到底有什么本事?
  6. ubuntu下使用filezilla上传文件权限问题(open for write: permission denied)
  7. SSL/TLS协议运行机制的概述
  8. Spark GraphX算法 - Connected Components(连通分支)算法
  9. 如何保证数据最终一致性(分布式事务)
  10. 如果华为完全没办法买到芯片,是否可以尝试做无芯手机?
  11. LeetCode 852 Peak Index in a Mountain Array 解题报告
  12. java实战项目案例-附带视频教学
  13. vb mysql 查询_VB数据库记录查询四法
  14. Firewalld 允许指定IP访问端口
  15. 移动硬盘坏了数据可以恢复吗?新方法一看便知
  16. 【AviUtl】动画效果,简易Glitch++(派生),学习笔记
  17. 什么是java?以及java的初步简单学习
  18. firebox插件使用笔记
  19. 基于乾坤的微前端+SpringBoot2.7整套解决方案的基础通用平台及组件
  20. 搜索引擎:高级搜索技巧(初)

热门文章

  1. 资讯的服务器维护指什么,资讯
  2. 低成本快速上链 智臻链开放联盟网络正式对外开放
  3. Go学习笔记_环境搭建
  4. 计算机类高水平文章,作为本科生的我,如何成功发表高水平会议论文
  5. 弘辽科技:什么是淘宝直通车卡位?有哪些卡位技巧?
  6. numpy array 增加一列(行)
  7. 改变IDEA模板光标停留的位置
  8. A-Priori算法及其优化(FP树)
  9. [附源码]java毕业设计旅游管理系统
  10. macOS 安装 brew步骤