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 类把屏幕空间的用户输入(鼠标拖拽点击或者触摸事件)转换为三维世界的相机移动 。它包含一些属性,可以启用/禁用某种用户输入,修改惯性、最小最大缩放距离等。
作者:Cesium实验室
链接:https://www.jianshu.com/p/1a31aa57a84b
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
Cesium官方教程6--相机的更多相关文章
- 关于Cesium 官方教程
最近一直在准备第一次QQ群的Cesium基础培训公开课,虽说使用Cesium也有段日子了,但是要说对Cesium了解有多深,还真不一定.原因是一直以来我都是用哪里学哪里.基于多年开发三维数字地球的底层 ...
- Cesium官方教程13--Cesium和Webpack
原文地址:https://cesiumjs.org/tutorials/cesium-and-webpack/ Cesium 和 Webpack Webpack是非常强大非常流行的JavaScript ...
- Cesium官方教程10--高级粒子特效
原文地址:https://cesiumjs.org/tutorials/Particle-Systems-More-Effects-Tutorial/ 高级粒子系统特效 这篇教程学习更多的效果,包括天 ...
- Cesium官方教程11--建模人员必读
原文地址:https://cesium.com/blog/2014/12/15/gltf-tips-for-artists/ 这篇文章是Branden Coker, an artist from AG ...
- Cesium官方教程9--粒子系统
原文地址:https://cesiumjs.org/tutorials/Particle-Systems-Tutorial/ 粒子系统介绍 这篇教程带你学习Cesium的粒子相关API,比如如何在你的 ...
- Cesium官方教程8-- 几何体和外观效果
原文地址:https://cesiumjs.org/tutorials/Geometry-and-Appearances/ 几何体和外观效果(Geometry and Appearances) 这篇教 ...
- Cesium官方教程7--三维模型
原文地址:https://cesiumjs.org/tutorials/3D-Models-Tutorial/ 三维模型 (3D Models) 这篇教程给大家介绍,如何在Cesium中通过Primi ...
- Cesium官方教程5--地形图层
原文地址:https://cesiumjs.org/tutorials/Terrain-Tutorial/ Cesium支持渐进流式加载和渲染全球高精度地形,并且包含海.湖.河等水面效果.相对2D地图 ...
- Cesium官方教程4--影像图层
原文地址:https://cesiumjs.org/tutorials/Imagery-Layers-Tutorial/ 影像图层 Cesium支持多种服务来源的高精度影像(地图)数据的加载和渲染.图 ...
随机推荐
- iOS音频学习笔记二:iOS SDK中与音频有关的相关框架
上层: Media Player Framework: 包含MPMoviePlayerController.MPMoviePlayerViewController.MPMusicPla ...
- [LeetCode] 45. Jump game II ☆☆☆☆☆(跳跃游戏 2)
https://leetcode-cn.com/problems/jump-game-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-b ...
- Android应用查看本地数据库
使用Android Studio 视图==>工具窗口 == >Device File Explorer ==> 文件在 data/data目录下,你的应用程序报名,右键save as ...
- java.lang.Override注解
@Override注解的作用 当你想重写父类的某个方法时,它可以帮你检查方法的正确性. 举例说明 比如说我们重写父类的toString()方法,但我们现在将toString这个方法名拼错了,这是它会在 ...
- [终章]进阶20-流程控制结构--if/case/while结构 - 三个while的存储过程案例(批量生成表单数据) - 随机长度的随机字符串的存储过程案例
. mysql 存储过程中尽量使用 @变量 而不用局部变量, @变量不容易报错!权限小,更改一下就报错! . sql中判断相等'=' ,用'=' 不用'=='. . #流程控制结构 /* 顺序结构: ...
- AJAX学习笔记——同源策略
同源策略 同源策略,所有浏览器都实行这个政策 最初,它的含义是指,A 网页设置的 Cookie,B 网页不能打开,除非这两个网页"同源".所谓"同源"指的是&q ...
- Git----常见工作管理总结
1.工作流程模式: 首先,可以试图用git push origin branch-name推送自己的修改 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并 如果合并有冲突, ...
- 读取Excel数据到DataTable
读取Excel数据到DataTable 代码 /// <summary> /// 获取指定路径.指定工作簿名称的Excel数据:取第一个sheet的数据 /// </summary& ...
- 记录从裸机到TensorFlow GPU版运行 的配置过程
实验室原来有一台装Ubuntu Server系统的服务器,安装有tensorflow,在使用过程中经常出现断网.死机.自动关机等毛病,忍无可忍,决定重装系统 配置如下:Dell工作站,Xeon-E5 ...
- QT中使用pri子工程
QT中使用pri子工程 使用子工程的作用是使得工程结构更加清晰,举个例子: 我制作了一个自定义控件,具备通用性,我打算把它用在日后的工程中.制作的这个控件需要用到头文件h.源文件c,资源文件qrc.图 ...