# cesium-相机系统

在二维GIS中移动视城或者进行空间漫游,只需设置视域范围中心点的经纬度坐标和图层等级,可以理解为只需确定视点位置即可,不存在视线方向问题。但在三维GIS中不仅需要确定视点位置,还要确定视线方向,如果目标物与视线方向相反.那么在视域中则看不到目标物。Cesium通过相机控制场景中的视域,旋转、缩放、平移等操作都可控制相机移动。当用户拖动地球移动时,其实是地球不动,相机在移动,这种相对运动产生场景移动的效果。Cesium具有默认的鼠标和触摸事件处理程序与摄像头交互。默认的相机操作是这样的:

  • 左键单击并拖动:移动整个地图
  • 右键单击并拖动:放大和缩小相机
  • 中轮滚动:放大和缩小相机
  • 中间点击并拖动:围绕地球表面的点旋转相机

# 相机的方向和位置

img

Cesium中orientation函数用于设定方向,不仅是相机方向,还包括模型的方向等。position函数用于设定相机位置。

Cesium将Orientation定义为Object。它通常包含heading、pitch和roll,这三者并不是必选参数,不设置具体参数则自动设为相应默认值。 可通过HeadingPitchRoll API查看相应属性。

  • pitch:围绕X轴旋转,也叫俯仰角,因为绕X轴旋转,可以控制飞机俯仰角,往上飞或者往下飞。

  • yaw:围绕Y轴旋转,也叫偏航角,因为绕Y轴旋转,可以控制飞机飞行方向,往左飞还是往右飞。

  • roll:围绕Z轴旋转,也叫翻滚角,因为绕Z轴旋转,可以控制飞机做翻滚旋转。

Cesium中相机方向orientation设定原理与右手笛卡儿坐标系原理相同,用heading替换yaw,但是含义相同,都是指水平旋转,Cesium中以正北为参照,即x轴所在方向。

  • heading:默认方向为正北,正角度为向东旋转,即水平旋转,也叫偏航角。

  • pitch:默认旋转角度为一90,即朝向地面,正角度为平面之上,负角度为平面之下,即上下旋转,也叫俯仰角。

  • roll:默认旋转角度为0,左右旋转.正角度向右旋转,负角度向左旋转,也叫翻滚角。

以上是orientation的含义,position是指相机位置的三维坐标(可以用经纬度和大地高表达)。这里通过setView方法给相机设定方位:

var position = Cesium.Cartesian3.fromDegrees(lon,lat,height);
viewer.camera.setView({
    destination: position,
    orientation: {
        heading: Cesium.Math.toRadians(0,0), // 默认值
        pitch: Cesium.Math.toRadians(-90.0), // 默认值
        roll: 0.0, // 默认值
    }
});
1
2
3
4
5
6
7
8
9

# 相机系统分类与用法

# setView

setView通过定义相机飞行目的点三维坐标(经纬度和大地高)和视线方向,将视角直接切换到所设定的视城范围内,没有空中飞行的过程,适用于快速切幕视角。

var position = Cesium.Cartesian3.fromDegrees(lon,lat,height);
viewer.camera.setView({
    destination: position, // 飞行目的地
    orientation: {
        heading: Cesium.Math.toRadians(0,0), // 默认值
        pitch: Cesium.Math.toRadians(-90.0), // 默认值
        roll: 0.0, // 默认值
    }
});
1
2
3
4
5
6
7
8
9

# viewBoundingSphere

viewBoundingSphere相机运动效果与setView类似,都是视域切换到目标点,没有视域飞行的过程,但是其设定方法与setView 有所不同。viewBoundingSphere函数必须设定模型的外接圆,viewBoundingSphere这种方式适用于室内浏览,因为 家内空间较小,相机移动的幅度不易控制。viewBoundingSphere可将相机固定在定点,视角绕点旋转360",实现定点环游。BoundingSphere简单说就是物体的外接球。viewBoundingSphere默认将视点置于外接球球心,可以设置偏称。以一个室内三维模型为例,加载数据完成后通过设定viewBoundingSphere实现定点环绕浏览:

var tileset = new Cesium.Cesium3DTileset({
    url: 'http://192.168.1.243:8088/data/point/demo01/tileset.json',
});
tileset.readyPromise.then(function(tileset){
    primitives.add(tileset);
    viewer.scene.primitives.add(primitives);
    viewer.camera.viewBoundingSphere(tileset.boundingSphere,new Cesium.HeadingPitchRange(-2.57,0,2));
});
1
2
3
4
5
6
7
8

# flyTo

setView是快速切换视角,fIyTo则具有空中飞行逐步切换视域的效果,可以设置飞行时间,相机则根据当前视点位置和目标视点位置自动设定飞行速度和飞行路线,实现巡游式视域切换。

viewer.scene.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(lon,lat,height),  // 设置视点位置,建议使用谷歌地球坐标位置无偏差
    duration:2,   //设置飞行持续时间,默认值会根据距离计算(单位秒)
    orientation : {
        heading : Cesium.Math.toRadians(120.0),//方向
        pitch : Cesium.Math.toRadians(-90.0),//倾斜角度
        roll : 0
    },
    complete:function(){
        //到达位置后执行的回调函数
    },
    cancle:function(){
        //如果取消飞行则会调用此函数
    },
    pitchAdjustHeight: -90,// 如果摄像机飞越高于该值,则调整俯仰角,并将地球保持在视域中
    maximumHeight: 5000, // 相机最大飞行高度
    flyOverLongitude: 100, //相机飞向目的地的过程中,必须强制经过东经100°子午线
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# lookAt

lookAt函数也是将视角固定在所设置的目的地点上,用户可以通过鼠标任意旋转视角方向,但是不会改变其位置。

var ceter = Cesium.Cartesian3.fromDgrees(lon,lat); // 设定相机目标点单的位置 
var heading = Cesium.Math.toRadians(50.0); //偏航角
var pitch Cesium.Math.toRadians(-90.0); //俯仰角
var range = 50.0; //距目标点水平面距离
viewer.camera.lookAt(center, new Cesium.HeadingPitchRange(heading,pitch,range));
1
2
3
4
5

# 键盘事件

三维场景开发中,通过键盘操纵相机视域移动是一个常规功能。Cesium为开发者定义了键盘事件,想要实现键盘事件需要设定相机参数,监听键盘事件并绑定相机参数。通常约定以下键盘事件:

  • W键向前移动相机
  • S键向后移动相机
  • A键向左移动相机
  • D键向右移动相机
  • Q键向上移动相机
  • E键向下移动相机

接下来通过具体代码设定键盘事件,实现相机移动翻转:

var ellipsoid = viewer.scene.globe.ellipsoid;//定义椭球
1

然后定义flags对象,设定具体相机事件。此处设置8个事件,分别是前移、后移、上移、下移左移、右移,左转和右转。

var flags= {
moveforward: false,
moveBackward: false,
moveUp: false,
noveDowm: false,
moveLeft: false,
noveRight: false, 
lokleft: false,
lokRight: false
};
// 将健盘健码绑定对应相机机事件
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';
    case 'G'.charCodeAt(0);
        return 'twistRight';
    case 'F'.charCodeAt(0);
        return 'twistLeft';
    case 37:
        return 'lookLeft';
    case 39:
        return 'lookRight';
    case 38:
        return 'lookUp';
    case 40:
        return 'lookDown';
    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] = true;
    }
},false);

//监听不同键码事件,并控制相应的相机事件
viewer clock.onTick.addEventListener(function(clock){
var camera = viewer.camera;
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);
    }
if (flags.lookLeft) (
    camera.lookLeft(moveRate);
    }
if (flags.lookRight) (
    camera.lookRight(moveRate);
    }
if (flags.twistRight) (
    camera.twistRight(moveRate);
    }
if (flags.twistLeft) (
    camera.twistLeft(moveRate);
    }
if (flags.lookUp) (
    camera.lookUp(moveRate);
    }
if (flags.lookDown) (
    camera.lookDown(moveRate);
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

这样就可以完成三维场景巡游。

上次更新时间: 2022年5月20日星期五上午11点16分