Cesium官方教程6--相機


相機(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); } 

lookRightlookUp方法需要一個旋轉角度的參數,單位是弧度。 我們把鼠標位置變換到了-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中關於相機的示例:

  • 相機教程 - 本教程對應的代碼。
  • 相機 - 相機飛行定位,可視范圍修改以及相機的參考空間等示例。

也可以查看下相機相關類的用戶手冊:

 
中國最專業的Cesium開發者社區




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM