使用cesium使用飞行漫游功能以及原地平滑转向
在cesium里面实现飞行漫游,由于没有找到合适的案例,自力更生,丰衣足食。
相机的移动主要两种方式:
setView,flyTo
其中flyTo测试了,感觉不合适,所以用了setView,当然只是自己的浅薄认识,如有错误,敬请指正。
废话不多说了,直接上代码,基本都能看懂吧,我尽量写了注释了。
另外代码和环境我都上传了,地址:https://download.csdn.net/download/dragonrxl/11579847
<!DOCTYPE html> <html lang="en"> <head> <!-- Use correct character set. --> <meta charset="utf-8"> <!-- Tell IE to use the latest, best version. --> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <!-- Make the application on mobile take up the full browser screen and disable user scaling. --> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> <title>cisium airplane trip</title> <script src="Build/Cesium/Cesium.js"></script> <style> @import url(Build/Cesium/Widgets/widgets.css); html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } .cesium-widget-credits{ display:none} /** 隐藏版权信息 **/ .cesium-viewer .cesium-widget-credits{ display:none } </style> </head> <body> <div id="cesiumContainer"></div> <script> var viewer = new Cesium.Viewer('cesiumContainer', { geocoder: false,//是否显示geocoder小器件,右上角查询按钮 homeButton:false,//是否显示Home按钮 sceneModePicker:false,//是否显示3D/2D选择器 baseLayerPicker:false,//是否显示图层选择器 navigationHelpButton:false,//是否显示右上角的帮助按钮 animation:false,//是否创建动画小器件,左下角仪表 creditContainer:"cesiumContainer",// 对应上面div的ID timeline:false,//是否显示时间轴 fullscreenButtion:false,//是否显示全屏按钮 vrButton:false, selectionIndicator : false,//是否显示选取指示器组件 }); // 上面配置选项可以控制部分控件是否显示 viewer.scene.debugShowFramesPerSecond = true;// 显示帧率 /** 默认使用bing地图,转换为google地图开始 **/ var google = new Cesium.UrlTemplateImageryProvider({ url : 'http://mt0.google.cn/vt/lyrs=s&hl=zh-CN&x={x}&y={y}&z={z}', tilingScheme : new Cesium.WebMercatorTilingScheme(), maximumLevel : 20 }); viewer.imageryLayers.addImageryProvider(google); /** 默认使用bing地图,转换为google地图结束 **/ /** 相机视角飞行 开始 **/ var marks = [ {lng: 116.812948,lat:36.550064, height:100, flytime:15},// height:相机高度(单位米) flytime:相机两个标注点飞行时间(单位秒) {lng: 116.812948,lat:36.560064, height:100, flytime:15}, {lng: 116.802948,lat:36.560064, height:100, flytime:15}, {lng: 116.802948,lat:36.550064, height:100, flytime:15}, ];// 地标集合 根据地标顺序来进行漫游 var marksIndex = 1; var pitchValue = -20; viewer.scene.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(marks[0].lng,marks[0].lat, marks[0].height), //定位坐标点,建议使用谷歌地球坐标位置无偏差 duration:7 //定位的时间间隔 }); setTimeout(function(){ flyExtent(); },7000); function flyExtent(){ // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值 var pitch = Cesium.Math.toRadians(pitchValue); // 时间间隔2秒钟 setExtentTime(marks[marksIndex].flytime); var Exection = function TimeExecution() { var preIndex = marksIndex - 1; if(marksIndex == 0){ preIndex = marks.length -1; } var heading = bearing(marks[preIndex].lat, marks[preIndex].lng, marks[marksIndex].lat, marks[marksIndex].lng); heading = Cesium.Math.toRadians(heading); // 当前已经过去的时间,单位s var delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime); var originLat = marksIndex == 0 ? marks[marks.length - 1].lat : marks[marksIndex-1].lat; var originLng = marksIndex == 0 ? marks[marks.length - 1].lng : marks[marksIndex-1].lng; var endPosition = Cesium.Cartesian3.fromDegrees( (originLng+(marks[marksIndex].lng-originLng)/marks[marksIndex].flytime*delTime), (originLat+(marks[marksIndex].lat-originLat)/marks[marksIndex].flytime*delTime), marks[marksIndex].height ); viewer.scene.camera.setView({ destination: endPosition, orientation: { heading: heading, pitch : pitch, } }); if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) { viewer.clock.onTick.removeEventListener(Exection); changeCameraHeading(); } }; viewer.clock.onTick.addEventListener(Exection); } // 相机原地定点转向 function changeCameraHeading(){ var nextIndex = marksIndex + 1; if(marksIndex == marks.length - 1){ nextIndex = 0; } // 计算两点之间的方向 var heading = bearing(marks[marksIndex].lat, marks[marksIndex].lng, marks[nextIndex].lat, marks[nextIndex].lng); // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值 var pitch = Cesium.Math.toRadians(pitchValue); // 给定飞行一周所需时间,比如10s, 那么每秒转动度数 var angle = (heading - Cesium.Math.toDegrees(viewer.camera.heading)) / 2; // 时间间隔2秒钟 setExtentTime(2); // 相机的当前heading var initialHeading = viewer.camera.heading; var Exection = function TimeExecution() { // 当前已经过去的时间,单位s var delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime); var heading = Cesium.Math.toRadians(delTime * angle) + initialHeading; viewer.scene.camera.setView({ orientation: { heading : heading, pitch : pitch, } }); if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) { viewer.clock.onTick.removeEventListener(Exection); marksIndex = ++marksIndex >= marks.length ? 0 : marksIndex; flyExtent(); } }; viewer.clock.onTick.addEventListener(Exection); } // 设置飞行的时间到viewer的时钟里 function setExtentTime(time){ var startTime = Cesium.JulianDate.fromDate(new Date()); var stopTime = Cesium.JulianDate.addSeconds(startTime, time, new Cesium.JulianDate()); viewer.clock.startTime = startTime.clone(); // 开始时间 viewer.clock.stopTime = stopTime.clone(); // 结速时间 viewer.clock.currentTime = startTime.clone(); // 当前时间 viewer.clock.clockRange = Cesium.ClockRange.CLAMPED; // 行为方式 viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK; // 时钟设置为当前系统时间; 忽略所有其他设置。 } /** 相机视角飞行 结束 **/ /** 飞行时 camera的方向调整(heading) 开始 **/ // Converts from degrees to radians. function toRadians(degrees) { return degrees * Math.PI / 180; } // Converts from radians to degrees. function toDegrees(radians) { return radians * 180 / Math.PI; } function bearing(startLat, startLng, destLat, destLng){ startLat = this.toRadians(startLat); startLng = this.toRadians(startLng); destLat = this.toRadians(destLat); destLng = this.toRadians(destLng); let y = Math.sin(destLng - startLng) * Math.cos(destLat); let x = Math.cos(startLat) * Math.sin(destLat) - Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng); let brng = Math.atan2(y, x); let brngDgr = this.toDegrees(brng); return (brngDgr + 360) % 360; } /** 飞行时 camera的方向调整(heading) 结束 **/ </script> </body> </html>