文章目录
CesiumJS 中的相机控制场景的视图。 有很多操作相机的方法,例如旋转,缩放,平移和飞到目的地。 CesiumJS 具有鼠标和触摸事件处理程序以与相机进行交互,并具有以编程方式操作相机的API。 了解如何使用 Camera API 和自定义相机控件。
Default camera behavior
在 Sandcastle 中打开 Hello World 示例,以浏览默认的相机控件。 默认值为:
Mouse Action | 3D | 2D | Columbus View |
---|---|---|---|
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 |
使用 setView 功能以编程方式设置摄像机的位置和方向。 destination 可以是 Cartesian3 或 Rectangle ,方向可以是航向/俯仰/滚动或方向/向上。 航向角,俯仰角和横滚角以弧度定义。 航向是从局部北向旋转,其中正角向东增加。 俯仰是从本地东西向平面的旋转。 正俯仰角在平面上方。 负俯仰角在平面下方。 横摇是绕局部东轴应用的第一次旋转。
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.setView({
destination : Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
orientation: {
heading : 0.0,
pitch : -Cesium.Math.PI_OVER_TWO,
roll : 0.0
}
});
Custom camera mouse or keyboard events
让我们创建自己的事件处理程序,使相机朝着鼠标的方向看,并在按键时向前,向后,向左,向右,向上和向下移动。 首先禁用默认事件处理程序。 添加以下代码(在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);
现在,当指示事件发生的标志为true时,我们想更新摄像机。 我们可以在时钟上向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);
}
lookRight 和 lookUp 方法采用一个以弧度为单位的参数,即旋转角度。 我们将鼠标坐标转换为(-1.0,1.0)范围,将坐标(0.0,0.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);
}
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);
}
// 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 代表摄影机当前位置,方向,参考系和视锥的状态。 上面的摄像机矢量在每个帧中都是正交的。
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);
Screen space camera controller
ScreenSpaceCameraController 将用户输入(例如鼠标和触摸)从窗口坐标转换为相机运动。 它包含用于启用和禁用不同类型的输入,修改惯量以及最小和最大缩放距离的属性。
Resources
查看Sandcastle中的相机示例:
- Camera Tutorial - 本教程中的代码示例。
- Camera - 可以飞到特定位置,查看范围并设置相机参考系的代码示例。
另外,请查阅参考文档: