1. 概述
Cesium的Camera案例,展示了其關於漫游器鏡頭的控制,能夠調整視圖的位置。這里改進了一下這個實例,使之能夠展示一些自己關注的興趣點的情況,並總結遇到的問題。
2. 實例
2.1. Camera.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> <meta name="description" content="Fly to a specified location or view a geographic rectangle."> <meta name="cesium-sandcastle-labels" content="Beginner, Tutorials, Showcases"> <title>Cesium Demo</title> <script type="text/javascript" src="../Build/Cesium/Cesium.js"></script> <style> @import url(../Build/Cesium/Widgets/widgets.css); html, body { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; font-family: sans-serif; background: #000; } .fullSize { display: block; position: absolute; top: 0; left: 0; border: none; width: 100%; height: 100%; } #toolbar { margin: 5px; padding: 2px 5px; position: absolute; } </style> </head> <body> <div id="cesiumContainer" class="fullSize"></div> <div id="toolbar"> <select id = "camera_select", class="cesium-button"> <option value="undefined"> 相機選項 </option> <option value="undefined"> 飛行至某一點——武漢大學 </option> <option value="undefined"> 飛行至某區域——武漢市 </option> <option value="undefined"> 設置相機點——華中科技大學 </option> <option value="undefined"> 設置相機區域——上海市 </option> <option value="undefined"> 從武大飛向華科 </option> </select> </div> <script src="Camera.js"></script> </body> </html>
這段代碼在數字地球展示組件的基礎上新添加了一個視圖控制的下拉列表框,選擇相應的選項能夠將當前的視圖調整到對應的位置。
2.2. Camera.js
//Add your ion access token from cesium.com/ion/ Cesium.Ion.defaultAccessToken = '你在Cesium申請的key'; var tdtKey = "你在天地圖申請的key"; 'use strict'; //默認BING影像地圖 var viewer = new Cesium.Viewer('cesiumContainer', { imageryProvider: Cesium.createWorldImagery({ style: Cesium.IonWorldImageryStyle.AERIAL }), baseLayerPicker: false }); //全球影像中文注記服務 var imageryLayers = viewer.scene.imageryLayers; var tdtAnnoLayer = imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({ url: "http://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={TileMatrix}&TILEROW={TileRow}&TILECOL={TileCol}&tk=" + tdtKey, layer: "tdtAnnoLayer", style: "default", format: "image/jpeg", tileMatrixSetID: "GoogleMapsCompatible" })); var camera_select = document.getElementById("camera_select"); if (camera_select) { camera_select.onchange = function gradeChange() { switch (camera_select.selectedIndex) { case 1: viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(114.35231209, 30.53542614, 5000.0), orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-90.0), roll: Cesium.Math.toRadians(0.0) } }); break; case 2: viewer.camera.flyTo({ destination: Cesium.Rectangle.fromDegrees(113.683333, 29.966667, 115.083333, 31.366667) }); break; case 3: viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(114.40782845, 30.51011682, 5000.0), orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-90.0), roll: Cesium.Math.toRadians(0.0) } }); break; case 4: viewer.camera.setView({ destination: Cesium.Rectangle.fromDegrees(120.86667, 30.66667, 122.2, 31.883333) }); break; case 5: { var whdxOptions = { destination: Cesium.Cartesian3.fromDegrees(114.35231209, 30.53542614, 5000.0), duration: 5, orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-90.0), roll: Cesium.Math.toRadians(0.0) } }; var hzkjdxOptions = { destination: Cesium.Cartesian3.fromDegrees(114.40782845, 30.51011682, 5000.0), orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-90.0), roll: Cesium.Math.toRadians(0.0) }, duration: 5, //flyOverLongitude: Cesium.Math.toRadians(60.0) }; whdxOptions.complete = function () { setTimeout(function () { viewer.camera.flyTo(hzkjdxOptions); }, 1000); }; // if (adjustPitch) { // tokyoOptions.pitchAdjustHeight = 1000; // laOptions.pitchAdjustHeight = 1000; // } viewer.camera.flyTo(whdxOptions); } break; default: break; } } }
這段代碼首先添加了Cesium.Viewer默認的Bing影像地圖和天地圖的中文標注;然后根據id獲取HTML頁面的下拉列表框控件camera_select;最后根據選項調整相應的相機視圖。這里展示了幾種調整視圖的方式。
2.2.1. 飛行至某一點
設置相機鏡頭逐漸從當前位置飛行到某一點是通過Cesium.Camera的flyTo()函數實現的,其具體的函數定義如下:

該函數傳入了鍵值對配置對象,其中destination、orientation這兩項,分別表示相機鏡頭的位置和姿態。本例中相應的代碼如下:
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(114.35231209, 30.53542614, 5000.0), orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-90.0), roll: Cesium.Math.toRadians(0.0) } });
這段設置相機視圖的代碼意思就是,將相機的位置移動到經緯度位置(114.35231209, 30.53542614),離地面5000米的點;航向角(heading)設置為0度,俯仰角(pitch)設置為-90度,滾轉角(roll)設置為0度。實際頁面的顯示效果為逐漸飛往某一點:

此時數字地球會顯示在武漢大學附近,視線看上去會垂直與地面,並且東西南北方向也基本上與常規地圖一致。實際上當不設置姿態參數orientation只設置位置參數destination也能達到同樣的效果,說明(0.0,-90.0,0.0)的三個姿態角是設置相機視圖的默認值。在Cesium的設定中,heading、pitch、roll的定義如下:

這說明航向角(heading)是繞Z后負方向旋轉的角度,俯仰角(pitch)是繞Y軸負方向旋轉的角度,滾轉角(roll)是繞X軸正方向旋轉的角度。那么問題來了,這個定義里面的X、Y、Z軸的指的是什么呢?我這里認為這個函數蘊含了一種視圖變換,使得基於相機的視空間坐標系成為一種類似於一種北東地站心坐標系(NED)坐標系,XYZ軸指的正是這個視空間坐標系的XYZ軸。在這個視空間坐標系中,Z軸垂直球面向下(Down),Y軸沿緯線指東(East),X軸沿經線向北(North),而位於視空間坐標系原點的相機的姿態為由南看向北。在這種情況下,只需要使相機繞Y軸正向旋轉90度,也就是俯仰角(pitch)設為90,就可以得到視線垂直於地圖,東西南北向正常的視圖。
2.2.2. 飛行至某區域
flyTo()函數另外一個很有用的功能就是根據設定的范圍顯示視圖,這在顯示特定空間的視圖時特別有用,例如加載的三維模型的范圍,一個地區的范圍等等。實現也很很簡單,只需要給位置參數destination傳入一個Cesium.Rectangle對象即可:
viewer.camera.flyTo({
destination: Cesium.Rectangle.fromDegrees(113.683333, 29.966667, 115.083333, 31.366667) });
將武漢市的經緯度范圍傳入,實際的顯示結果如下:

2.2.3. 兩地之間飛行
flyTo()函數還可以傳入一個配置項complete,可以給其設定一個飛行結束后再運行的函數,通過這個配置項可以實現兩地或多地飛行:
var whdxOptions = { destination: Cesium.Cartesian3.fromDegrees(114.35231209, 30.53542614, 5000.0), duration: 5, orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-90.0), roll: Cesium.Math.toRadians(0.0) } }; var hzkjdxOptions = { destination: Cesium.Cartesian3.fromDegrees(114.40782845, 30.51011682, 5000.0), orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-90.0), roll: Cesium.Math.toRadians(0.0) }, duration: 5, //flyOverLongitude: Cesium.Math.toRadians(60.0) }; whdxOptions.complete = function () { setTimeout(function () { viewer.camera.flyTo(hzkjdxOptions); }, 1000); }; // if (adjustPitch) { // tokyoOptions.pitchAdjustHeight = 1000; // laOptions.pitchAdjustHeight = 1000; // } viewer.camera.flyTo(whdxOptions);
這段代碼分別定義了兩個飛行配置項whdxOptions和hzkjdxOptions,並且給whdxOptions的complete項配置了一個函數,表示完成1S之后,自動進行hzkjdxOptions的飛行。運行結果如下圖所示:


2.2.4. 設置視圖到某一點
設置當前視圖通過setView()函數實現的,它跟flyTo()最大的不同是沒有持續時間,沒有飛行過程,是立即生效的。其具體的配置選項也比較相似,都是需要設置位置以及姿態:
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(114.40782845, 30.51011682, 5000.0), orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-90.0), roll: Cesium.Math.toRadians(0.0) } });
2.2.5. 設置視圖到某區域
設置具體的顯示范圍,也是立即生效,這兩個部分因為與flyTo()函數比較類似,就不再具體講解了。
viewer.camera.setView({
destination: Cesium.Rectangle.fromDegrees(120.86667, 30.66667, 122.2, 31.883333) });
3. 其他
3.1. 事件及相應函數
Cesium.Camera還提供了當前視圖發生變化的事件changed、視圖發生移動的事件moveStart/moveEnd,它們都可以通過addEventListener()給其添加相應的響應函數。
3.2. setReferenceFrame
自帶案例Camera中還提供了另外一種視圖控制方式:
function setReferenceFrame() { Sandcastle.declare(setReferenceFrame); var center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883); var transform = Cesium.Transforms.eastNorthUpToFixedFrame(center); // View in east-north-up frame var camera = viewer.camera; camera.constrainedAxis = Cesium.Cartesian3.UNIT_Z; camera.lookAtTransform(transform, new Cesium.Cartesian3(-120000.0, -120000.0, 120000.0)); // Show reference frame. Not required. referenceFramePrimitive = scene.primitives.add(new Cesium.DebugModelMatrixPrimitive({ modelMatrix: transform, length: 100000.0 })); }
這段代碼的意思是選定一個經緯度的點,可以計算出以該點為中心的東北天(ENU)站心坐標系與地心坐標系的轉換矩陣,將這個矩陣傳入給Cesium.Camera的lookAtTransform函數,從而達到設置視圖的目的。但是這樣做會導致當前世界坐標系發生變化,當前漫游器的鍵鼠交互操作不再以地心坐標系原點為中心,而以站心坐標系的原點為中心,導致這個時候的鍵鼠交互操作難以操作。
3.3. viewInICRF
Cesium默認是基於ITRF,也就是國際地球地心參考框架。自帶案例還提供了一種將其轉換為ICRF參考框架的視圖設置方式。關於ICRF我也不是很了解,查閱網上資料只知道是一種原點在太陽系的質心的天文參考框架,留待以后需要用到的時候再研究。
4. 參考
[1]. 北東地/東北天兩種導航坐標系與姿態轉換
[2]. Cesium中的相機—HeadingPitchRoll
[3]. Cesium類HeadingPitchRoll及heading、pitch、roll等參數詳解
https://www.cnblogs.com/charlee44/p/12108726.html