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); }
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中關於相機的示例:
也可以檢視下相機相關類的使用者手冊:
中國最專業的Cesium開發者社群