Cesium相机(五)

admin0条评论 8,127 次浏览

相机

Cesium中的相机控制场景中的视图。操作相机的方法很多,例如旋转,缩放,平移和飞行到目的地。铯具有默认的鼠标和触摸事件处理程序与摄像头交互,以及一个API以编程方式操作摄像头。本教程介绍相机概念和相关的Cesium API。

快速开始

我们从一个例子开始。在Sandcastle中打开Hello World示例。默认情况下,场景处理相机的鼠标和触摸输入。默认值是:

  • 左键单击并拖动 – 以3D形式在全球范围内旋转相机,然后在2D和Columbus视图中将相机翻转过地图表面。
  • 右键单击并拖动 – 放大和缩小相机。
  • 中间轮滚动 – 也放大和缩小相机。
  • 中点击并拖动 – 围绕地球表面上的点旋转摄像机。

我们可以用该setView功能以编程方式设置摄像机的位置和方向。这些论据是目的地和选择。的位置可以是的一个实例Cartesian3Rectangle,和取向可以是航向/俯仰/卷或方向/向上。标题,俯仰角度和滚转角度需要以弧度表示。标题是从正北角向东增加的局部北方的旋转。沥青是从当地东北飞机的旋转。正俯仰角在平面之上。负桨距角低于平面。滚动是关于当地东方轴线应用的第一个旋转。例如,用笛卡尔位置设置视图如下所示:

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参数的默认值是当前相机的位置,标题,俯仰和滚动。

最常见的用例是设置摄像头位置朝向地球的方向朝下,标题朝向北方:

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;

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

创建键盘事件处理程序来切换相机移动的标志。我们将为以下键和行为设置标志:

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

现在我们要在指示事件发生的标志为真时更新摄像头。我们可以onTick在包含以下代码的时钟上向事件添加侦听器:

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

该方法lookRightlookUp采取以弧度为单位的单个参数,它是旋转的角度。我们使用坐标(0.0,0.0)将鼠标坐标转换为范围(-1.0,1.0),并位于画布中心。鼠标离开中心的距离决定了转弯的速度。靠近中心的位置会使相机速度变慢,而离中心越远则相机移动速度越快。

完成后,我们添加代码来移动相机的位置。还要将此添加到事件侦听器函数中:

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

moveForwardmoveBackwardmoveUpmoveDownmoveLeft,和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);
    }

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

查看Sandcastle中的完整示例

相机

相机表示相机的当前位置,方位,参考帧,和视锥的状态。

  • move*zoom*功能沿其方向或给定矢量平移摄像机的位置。方向保持不变。

移动

  • look*twist*关于方向,向上或右载体功能旋转取向。职位保持不变。

捻

  • rotate*功能围绕给定的矢量的位置和方向。

旋转

注意:上面的相机矢量在每一帧中都是正交的。

  • 给定范围或位置和目标的相机位置和方向的功能。例如:
    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);
    
  • 通过像素创建相机位置的光线的功能。这对于挑选很有用,例如:
    // find intersection of the pixel picked and an ellipsoid
    var ray = camera.getPickRay(mousePosition);
    var intersection = Cesium.IntersectionTests.rayEllipsoid(ray, Cesium.Ellipsoid.WGS84);
    

屏幕空间相机控制器

所述ScreenSpaceCameraController转换用户输入,如鼠标和触摸,从窗口坐标到相机运动。它包含用于启用/禁用不同类型输入的属性,修改惯量以及最小和最大缩放距离。

资源

查看Sandcastle中的相机示例:

  • 相机教程 – 本教程中的代码示例。
  • 相机 – 代码示例可以飞到位置,查看范围和设置相机的参考框架。

另外,请查阅参考文档:


分类目录