相机(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); } 

lookRightlookUp方法需要一个旋转角度的参数,单位是弧度。 我们把鼠标位置变换到了-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
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转载于:https://www.cnblogs.com/telwanggs/p/11290052.html

Cesium官方教程6--相机相关推荐

  1. Cesium官方教程8-- 几何体和外观效果

    原文地址:https://cesiumjs.org/tutorials/Geometry-and-Appearances/ 几何体和外观效果(Geometry and Appearances) 这篇教 ...

  2. Cesium官方教程9--粒子系统

    原文地址:https://cesiumjs.org/tutorials/Particle-Systems-Tutorial/ 粒子系统介绍 这篇教程带你学习Cesium的粒子相关API,比如如何在你的 ...

  3. basler相机参数简要中文说明_附下载| OpenCV最新中文版官方教程

    OpenCV是计算机视觉中经典的专用库,然而其中文版官方教程久久不来.近日,一款最新OpenCV4.1 版本的完整中文版官方教程出炉,读者朋友可以更好的学习了解OpenCV相关细节.教程根据官方提供的 ...

  4. Cesium基础教程

    一.概述 Cesium是国外一个基于javascript的地图引擎,支持3D.2D.2.5D形式的展示,可以自行绘制图形.高亮区域,并提供良好的触摸支持,并支持大多数的浏览器和移动端. Cesium ...

  5. opencv python下载_[福利] OpenCV4 Python 最新中文版官方教程来了(附下载)

    教程简介 OpenCV 是计算机视觉中经典的专用库,然而其中文版官方教程久久不来.近日,一款最新 OpenCV4.1 版本的完整中文版官方教程出炉,读者朋友可以更好的学习了解 OpenCV 相关细节. ...

  6. unity官方教程-TANKS(一)

    unity官方教程TANKS,难度系数中阶. 跟着官方教程学习Unity,通过本教程你可以学会使用Unity开发游戏的基本流程. 一.环境 Unity 版本 > 5.2 Asset Store ...

  7. Unity官方教程Ruby大冒险的自学笔记

    Unity官方教程Ruby大冒险的自学笔记 一. //正确例子: void Update(){//获取运动矢量moveX = Input.GetAxisRaw("Horizontal&quo ...

  8. opencv python教程-OpenCV4 Python 最新中文版官方教程来了(附下载)

    教程简介 OpenCV 是计算机视觉中经典的专用库,然而其中文版官方教程久久不来.近日,一款最新 OpenCV4.1 版本的完整中文版官方教程出炉,读者朋友可以更好的学习了解 OpenCV 相关细节. ...

  9. Unity3D官方教程爬坑

    全是在学官教时遇到的坑,然后数小时后爬出来.同时会添加到处学来的的Unity技巧 ---------------------------------------------------------- ...

最新文章

  1. R语言ggplot2可视化facet间隔设置语法实战
  2. 2016年3月9日作业
  3. ip代理服务器软件25探索云速捷_IP代理在实际使用过程中会面临的问题,如何准确挑选和使用代理IP...
  4. java最终考核项目(实现商品管理系统)
  5. Python的第一种数据类型——Number(数字)
  6. Log4J入门教程(二) 参数讲解
  7. apktool重新打包,error:No resource identifier found for attribute ‘compileSdkVersionCodename‘ in package
  8. React之初始化state
  9. printstream_Java PrintStream clearError()方法与示例
  10. 详解4种微服务框架接入Istio方案
  11. 2021款iPad Pro跑分曝光:远超安卓阵营产品
  12. sql脚本过大,无法打开的解决方法
  13. 【实践】HMM模型在贝壳对话系统中的应用
  14. 按位与、或、异或等运算方法(转)
  15. 测试用rtmp直播源
  16. 磁带机故障灯解决方法
  17. html邮件模板美化,设计利器:定制你的炫酷邮件模板
  18. JavaScript通过extend和super实现继承
  19. win10网络重置后无法上网
  20. reshape2揉数据

热门文章

  1. Hive之管理表 外部表 分区表
  2. 用php mui ajax注册登录页面,ajax实现简单登录页面
  3. 关于FPGA核心bug解决
  4. (81)什么是原型验证?
  5. (50)IO的延迟约束(输入延迟约束)
  6. matplotlib绘制虚线_[Matplotlib习题]虚线绘图练习
  7. php怎么将网页变成图片格式,php如何实现图片格式转换
  8. jqgrid 编辑列拿不到值_如何在DAX Stadio和Excel中返回表和度量值?
  9. 【CCS】CCS全局搜索
  10. ubuntu10.04下 简单配置samba