相機(Camera)
相機控制了場景的觀察視角。有很多相機操控方法,比如旋轉、縮放、平移以及飛行定位。Cesium默認支持使用鼠標和觸摸事件控制相機。Cesium也提供了一套可編程的相機控制API。這篇教程就是介紹相機相關知識,以及API。
快速開始
開始示例。打開Sandcastle的 Hello World 示例。默認場景按照下述方式處理鼠標和處理事件:
左鍵單擊和拖拽
- 沿着地球表面平移(調整相機位置).
右鍵單擊和拖拽
- 相機放大縮小(調整相機距離).
滾輪
- 相機放大縮小(調整相機距離).
中間按下和拖拽
- 圍繞地球表面旋轉相機(調整相機方向)。
使用setView
方法可以設置相機位置和朝向。需要傳遞的參數是目標點和朝向。位置參數需要傳一個Cartesian3
或者 Rectangle
類的實例。朝向要么是 heading/pitch/roll 歐拉角 ,要么是 朝向向量/向上向量。heading/pitch/roll 的單位是弧度。Heading是當前方向 由北向東旋轉的角度。Pitch 是方向和水平平面的夾角。Pitch為正 表示方向向量指向水平平面上方,反之表示方向向量指向平面下方。Roll 是方向向量以正東方向為軸的旋轉角度。比如我們可以按照下面的代碼設置相機:
camera.setView({ destination : new Cesium.Cartesian3(x, y, z), orientation: { heading : headingAngle, pitch : pitchAngle, roll : rollAngle } });
位置屬性也可以設置為一個矩形區域:
viewer.camera.setView({ destination : Cesium.Rectangle.fromDegrees(west, south, east, north), orientation: { heading : headingAngle, pitch : pitchAngle, roll : rollAngle } });
所有參數都是可選的,如果哪個參數沒有設置或者設置undefined
,那么就使用當前相機的對應屬性去計算。
把相機垂直向下俯視,Heading設置為正北方向是最常見的設置參數:
camera.setView({ destination : Cesium.Cartesian3.fromDegrees(longitude, latitude, height), orientation: { heading : 0.0, pitch : -Cesium.Math.PI_OVER_TWO, roll : 0.0 } });
自定義相機的 鼠標\鍵盤事件
下來,我們創建一個自定義的相機控制方式,鼠標位置控制了相機前進方向,使用鍵盤來控制相機的前進,后退、向左、向右、向上、向下移動。先把默認的相機事件禁用。在var viewer = ...
之后添加下面的代碼:
var scene = viewer.scene; var canvas = viewer.canvas; canvas.setAttribute('tabindex', '0'); // needed to put focus on the canvas canvas.onclick = function() { canvas.focus(); }; var ellipsoid = viewer.scene.globe.ellipsoid; // 禁用默認相機控制事件 scene.screenSpaceCameraController.enableRotate = false; scene.screenSpaceCameraController.enableTranslate = false; scene.screenSpaceCameraController.enableZoom = false; scene.screenSpaceCameraController.enableTilt = false; scene.screenSpaceCameraController.enableLook = false;
下來,我們創建幾個變量記錄當前相機位置,和一些狀態變量來標記當前相機是如何移動。
var startMousePosition; var mousePosition; var flags = { looking : false, moveForward : false, moveBackward : false, moveUp : false, moveDown : false, moveLeft : false, moveRight : false };
增加一個事件處理器,當鼠標左鍵點擊的時候,存儲當前相機位置,並且設置looking狀態。
var handler = new Cesium.ScreenSpaceEventHandler(canvas); handler.setInputAction(function(movement) { flags.looking = true; mousePosition = startMousePosition = Cesium.Cartesian3.clone(movement.position); }, Cesium.ScreenSpaceEventType.LEFT_DOWN); handler.setInputAction(function(movement) { mousePosition = movement.endPosition; }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); handler.setInputAction(function(position) { flags.looking = false; }, Cesium.ScreenSpaceEventType.LEFT_UP);
增加一個鍵盤事件,去切換相機移動的狀態類型,根據下面鍵盤配置來設置:
w
前進s
后退a
向左移動d
向右移動q
向上移動e
向下移動
function getFlagForKeyCode(keyCode) { switch (keyCode) { case 'W'.charCodeAt(0): return 'moveForward'; case 'S'.charCodeAt(0): return 'moveBackward'; case 'Q'.charCodeAt(0): return 'moveUp'; case 'E'.charCodeAt(0): return 'moveDown'; case 'D'.charCodeAt(0): return 'moveRight'; case 'A'.charCodeAt(0): return 'moveLeft'; default: return undefined; } } document.addEventListener('keydown', function(e) { var flagName = getFlagForKeyCode(e.keyCode); if (typeof flagName !== 'undefined') { flags[flagName] = true; } }, false); document.addEventListener('keyup', function(e) { var flagName = getFlagForKeyCode(e.keyCode); if (typeof flagName !== 'undefined') { flags[flagName] = false; } }, false);
現在當這些狀態變量設置為true的時候,就需要更新相機的位置。使用下面代碼增加一個onTick
事件:
viewer.clock.onTick.addEventListener(function(clock) { var camera = viewer.camera; });
接着,確保相機一直是沿着鼠標方向。把下面的代碼添加到上面的事件處理函數里:
if (flags.looking) { var width = canvas.clientWidth; var height = canvas.clientHeight; // 鼠標點擊時,這個坐標計算得到0,0. var x = (mousePosition.x - startMousePosition.x) / width; var y = -(mousePosition.y - startMousePosition.y) / height; var lookFactor = 0.05; camera.lookRight(x * lookFactor); camera.lookUp(y * lookFactor); }
lookRight
和lookUp
方法需要一個旋轉角度的參數,單位是弧度。 我們把鼠標位置變換到了-1,1之間,0,0坐標就是窗口(canvas)的中心點。把鼠標和中心位置之間的距離當作旋轉的速度。距離中心越近旋轉越慢,距離越遠旋轉越快。
下來我們把相機移動的代碼也加上:
// 依據相機所在絕對高度來決定相機的運行速度 var cameraHeight = ellipsoid.cartesianToCartographic(camera.position).height; var moveRate = cameraHeight / 100.0; if (flags.moveForward) { camera.moveForward(moveRate); } if (flags.moveBackward) { camera.moveBackward(moveRate); } if (flags.moveUp) { camera.moveUp(moveRate); } if (flags.moveDown) { camera.moveDown(moveRate); } if (flags.moveLeft) { camera.moveLeft(moveRate); } if (flags.moveRight) { camera.moveRight(moveRate); }
moveForward
, moveBackward
,moveUp
, moveDown
, moveLeft
, moveRight
這些方法需要傳一個移動距離參數,單位為米。通過相機當前位置的絕對高程決定每次按下按鍵的移動距離。距離地面越近,每次移動的位置就越少。
完整代碼如下:
var viewer = new Cesium.Viewer('cesiumContainer'); var scene = viewer.scene; var canvas = viewer.canvas; canvas.setAttribute('tabindex', '0'); // needed to put focus on the canvas canvas.onclick = function() { canvas.focus(); }; var ellipsoid = viewer.scene.globe.ellipsoid; // disable the default event handlers scene.screenSpaceCameraController.enableRotate = false; scene.screenSpaceCameraController.enableTranslate = false; scene.screenSpaceCameraController.enableZoom = false; scene.screenSpaceCameraController.enableTilt = false; scene.screenSpaceCameraController.enableLook = false; var startMousePosition; var mousePosition; var flags = { looking : false, moveForward : false, moveBackward : false, moveUp : false, moveDown : false, moveLeft : false, moveRight : false }; var handler = new Cesium.ScreenSpaceEventHandler(canvas); handler.setInputAction(function(movement) { flags.looking = true; mousePosition = startMousePosition = Cesium.Cartesian3.clone(movement.position); }, Cesium.ScreenSpaceEventType.LEFT_DOWN); handler.setInputAction(function(movement) { mousePosition = movement.endPosition; }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); handler.setInputAction(function(position) { flags.looking = false; }, Cesium.ScreenSpaceEventType.LEFT_UP); function getFlagForKeyCode(keyCode) { switch (keyCode) { case 'W'.charCodeAt(0): return 'moveForward'; case 'S'.charCodeAt(0): return 'moveBackward'; case 'Q'.charCodeAt(0): return 'moveUp'; case 'E'.charCodeAt(0): return 'moveDown'; case 'D'.charCodeAt(0): return 'moveRight'; case 'A'.charCodeAt(0): return 'moveLeft'; default: return undefined; } } document.addEventListener('keydown', function(e) { var flagName = getFlagForKeyCode(e.keyCode); if (typeof flagName !== 'undefined') { flags[flagName] = true; } }, false); document.addEventListener('keyup', function(e) { var flagName = getFlagForKeyCode(e.keyCode); if (typeof flagName !== 'undefined') { flags[flagName] = false; } }, false); viewer.clock.onTick.addEventListener(function(clock) { var camera = viewer.camera; if (flags.looking) { var width = canvas.clientWidth; var height = canvas.clientHeight; // Coordinate (0.0, 0.0) will be where the mouse was clicked. var x = (mousePosition.x - startMousePosition.x) / width; var y = -(mousePosition.y - startMousePosition.y) / height; var lookFactor = 0.05; camera.lookRight(x * lookFactor); camera.lookUp(y * lookFactor); } var cameraHeight = ellipsoid.cartesianToCartographic(camera.position).height; var moveRate = cameraHeight / 100.0; if (flags.moveForward) { camera.moveForward(moveRate); } if (flags.moveBackward) { camera.moveBackward(moveRate); } if (flags.moveUp) { camera.moveUp(moveRate); } if (flags.moveDown) { camera.moveDown(moveRate); } if (flags.moveLeft) { camera.moveLeft(moveRate); } if (flags.moveRight) { camera.moveRight(moveRate); } });
可以看下Sandcastle的 完整實例 。
Camera類
Camera類描述了相機的當前狀態,包包括 位置( position),朝向( orientation), 參考空間( reference frame), 視錐體(view frustum).
move*
和zoom*
方法的作用:沿着相機方向或者某個給定向量來平移相機的位置。 相機朝向不變。

look*
和twist*
方法的作用:旋轉相機朝向,向前向量(direction),向上向量(up),向右向量(right)都會改變。相機位置保持不變。

rotate*
方法的作用:相對一個給定的向量,旋轉相機的位置和朝向。

注意:Cesium每幀會保證相機的三個朝向向量是正交的。
Note: The camera vectors above are orthonormal in each frame.
-
修改相機位置,設置一個對象位置或者范圍:
var west = Cesium.Math.toRadians(-77.0); var south = Cesium.Math.toRadians(38.0); var east = Cesium.Math.toRadians(-72.0); var north = Cesium.Math.toRadians(42.0); var extent = new Cesium.Extent(west, south, east, north); camera.viewExtent(extent, Cesium.Ellipsoid.WGS84);
-
根據一個屏幕坐標創建一個從相機位置發出的射線。在拾取過程中非常有用:
// 計算相機射線和橢球體相交點 var ray = camera.getPickRay(mousePosition); var intersection = Cesium.IntersectionTests.rayEllipsoid(ray, Cesium.Ellipsoid.WGS84);
屏幕控件相機控制器
ScreenSpaceCameraController 類把屏幕空間的用戶輸入(鼠標拖拽點擊或者觸摸事件)轉換為三維世界的相機移動 。它包含一些屬性,可以啟用/禁用某種用戶輸入,修改慣性、最小最大縮放距離等。
資源
Sandcastle中關於相機的示例:
也可以查看下相機相關類的用戶手冊:
