Cesium中級教程3 - Camera - 相機(攝像機)


Cesium中文網:http://cesiumcn.org/ | 國內快速訪問:http://cesium.coinidea.com/

Camera

CesiumJS中的Camera控制場景的視圖。有很多方法可以操作Camera,如旋轉(rotate)、縮放(zoom)、平移(pan)和飛到目的地(flyTo)。CesiumJS有鼠標和觸摸事件用來處理與Camrea的交互,還有API來以編程方式操作攝像機。了解如何使用Camera API和自定義相機控制(Camera controls)。

默認Camera行為

打開Sandcastle中的Hello World樣例用來體驗默認的相機控制。默認操作方式如下:

鼠標操作 3D 2D Columbus視角
Left click + drag Rotate around the globe Translate over the map Translate over the map
Right click + drag Zoom in and out Zoom in and out Zoom in and out
Middle wheel scrolling Zoom in and out Zoom in and out Zoom in and out
Middle click + drag Tilt the globe No action Tilt the map
鼠標操作 3D 2D Columbus視角
左鍵 + 拖拽 旋轉地球 在地圖上移動 在地圖上移動
右鍵 + 拖拽 縮放 縮放 縮放
中鍵滾輪 縮放 縮放 縮放
中鍵 + 拖拽 傾斜地球 無操作 傾斜地球

使用setView函數設置Camera的位置和方向。destination可以是Cartesian3Rectangleorientation可以是heading/pitch/rolldirection/up。航向角、俯仰角和橫滾角以弧度定義。航向角是從正角度向東增加的局部北向旋轉。俯仰角是指從局部的東北平面開始的旋轉。正俯仰角在平面上方。負俯仰角在平面以下。很滾叫是圍繞局部東軸應用的第一個旋轉。

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
    }
});

上述的所有參數都是可選的。如果未指定,參數值將被設為默認值用戶當前Camera的位置和方向。

自定義Camera鼠標或者鍵盤事件

創建我們自己的事件控制,根據鼠標的朝向用於控制Camera的朝向,鍵盤的按鍵控制Camera向前、向左、向右、向上,以及向下。首先從禁用默認事件操作開始。在(javascript var viewe=...)之后添加下列代碼:

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;

創建變量記錄當前鼠標位置,然后標記並跟隨Camera移動軌跡:

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);

創建鍵盤事件控制用戶切換Camera移動標記。我們為下列按鍵和行為設置了標記:

  1. w Camera向前。
  2. s Camera向后。
  3. a Camera向左。
  4. d Camera向右。
  5. q Camera向上。
  6. e Camera向下。
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是,我們更新(update)camera。我們新增**onTick的監聽事件在clock中:

viewer.clock.onTick.addEventListener(function(clock) {
    var camera = viewer.camera;
});

接下來,我們讓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);
}

lookRightlookUp只需要一個角度參數用於表示旋轉的角度。我們將鼠標坐標轉換為范圍(-1.0,1.0),坐標(0.0,0.0)位於畫布的中心。鼠標距中心的距離決定了旋轉的速度。靠近中心的位置移動Camera的速度較慢,而遠離中心的位置移動Camera的速度較快。

最后,添加代碼用於移動Camera的位置。然后添加下列代碼到事件響應函數:

// Change movement speed based on the distance of the camera to the surface of the ellipsoid.
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);
}

moveForwardmoveBackwardmoveUpmoveDownmoveLeftmoveRight方法只需要一個距離參數(米)用於移動Camera的距離。當每一個按鍵被按下時,Camera就會在球體表面移動固定的距離。Camera離地面越近,移動的速度就越慢。

完整的代碼如下:

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);
    }

    // Change movement speed based on the distance of the camera to the surface of the ellipsoid.
    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);
    }
});

完整代碼請訪問)

Camera

Camera表示Camera當前位置、方向、參考幀和視圖截錐的狀態。上面的Camera向量在每幀中都是正交的。
move**和zoom**函數平移Camera的位置按照它的方向或指定的方向矢量。方向保持固定不變。

look**和twist**函數旋轉Camera的方向比如向上、或向右矢量。位置保持固定不變。

*rotate**函數玄幻位置和方向基於給定矢量。

函數設置Camera給定范圍或位置和目標的Camera位置和方向。例如:

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);

創建變量ray,通過像素拾取Camera的位置。該方法可用於拾取,例如:

// find intersection of the pixel picked and an ellipsoid
var ray = camera.getPickRay(mousePosition);
var intersection = Cesium.IntersectionTests.rayEllipsoid(ray, Cesium.Ellipsoid.WGS84);

Screen space camera controller

ScreenSpaceCameraController將用戶輸入(如鼠標和觸摸)從窗口坐標轉換為Camera運動。它包含用於啟用和禁用不同類型輸入、修改慣性量以及最小和最大縮放距離的屬性。

資源

可在Sandcastle中查看camera樣例代碼:

  1. Camera Tutorial
  2. Camera

API文檔:

  1. Camera
  2. ScreenSpaceCameraController

Cesium中文網交流QQ群:807482793
Cesium中文網:http://cesiumcn.org/ | 國內快速訪問:http://cesium.coinidea.com/


免責聲明!

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



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