Cesium高级教程-渲染流程-程序入口
Viewer类
一般情况下,我们创建Cesium应用程序都是从new Cesium.Viewer()
开始的,Viewer
类我们称之为视图容器,可以将其看着一个大容器,承载了Cesium应用的所有内容。
打开Viewer
类的源码,可以看到在其构造函数中,先根据外部传入的container
参数获取到顶级的容器元素,获取到顶级容器元素后首先在该容器中添加了很多div
元素作为Cesium部件
的父容器,然后开始创建Cesium的部件对象。
核心部件
首先是创建CesiumWidget
部件,这是Cesium中最核心的部件,是三维场景渲染的入口。
//源码文件所在位置 packages\widgets\Source\Viewer\Viewer.js
function Viewer(container, options) {
...
container = getElement(container);
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
...
const viewerContainer = document.createElement("div");
viewerContainer.className = "cesium-viewer";
container.appendChild(viewerContainer);
// Cesium widget container
const cesiumWidgetContainer = document.createElement("div");
cesiumWidgetContainer.className = "cesium-viewer-cesiumWidgetContainer";
viewerContainer.appendChild(cesiumWidgetContainer);
// Bottom container
const bottomContainer = document.createElement("div");
bottomContainer.className = "cesium-viewer-bottom";
viewerContainer.appendChild(bottomContainer);
const scene3DOnly = defaultValue(options.scene3DOnly, false);
...
// Cesium widget
const cesiumWidget = new CesiumWidget(cesiumWidgetContainer, {
baseLayer:
(createBaseLayerPicker &&
defined(options.selectedImageryProviderViewModel)) ||
defined(options.baseLayer) ||
defined(options.imageryProvider)
? false
: undefined,
clock: clock,
skyBox: options.skyBox,
skyAtmosphere: options.skyAtmosphere,
sceneMode: options.sceneMode,
ellipsoid: options.ellipsoid,
mapProjection: options.mapProjection,
globe: options.globe,
orderIndependentTranslucency: options.orderIndependentTranslucency,
contextOptions: options.contextOptions,
useDefaultRenderLoop: options.useDefaultRenderLoop,
targetFrameRate: options.targetFrameRate,
showRenderLoopErrors: options.showRenderLoopErrors,
useBrowserRecommendedResolution: options.useBrowserRecommendedResolution,
creditContainer: defined(options.creditContainer)
? options.creditContainer
: bottomContainer,
creditViewport: options.creditViewport,
scene3DOnly: scene3DOnly,
shadows: options.shadows,
terrainShadows: options.terrainShadows,
mapMode2D: options.mapMode2D,
blurActiveElementOnCanvasFocus: options.blurActiveElementOnCanvasFocus,
requestRenderMode: options.requestRenderMode,
maximumRenderTimeChange: options.maximumRenderTimeChange,
depthPlaneEllipsoidOffset: options.depthPlaneEllipsoidOffset,
msaaSamples: options.msaaSamples,
});
let dataSourceCollection = options.dataSources;
let destroyDataSourceCollection = false;
if (!defined(dataSourceCollection)) {
dataSourceCollection = new DataSourceCollection();
destroyDataSourceCollection = true;
}
const scene = cesiumWidget.scene;
const dataSourceDisplay = new DataSourceDisplay({
scene: scene,
dataSourceCollection: dataSourceCollection,
});
...
}
创建完CesiumWidget
部件后,从该部件中获取scene
场景对象,然后创建默认的数据源集合,数据源集合被绑定到了一个DataSourceDisplay
对象上,表示由该DataSourceDisplay
来解析默认的数据源集合。
基本部件
除了核心的场景渲染部件
(CesiumWidget
)外,Cesium还自带很多小部件(比如时间线,搜索框等),在后去到scene
根据传入的条件进行各个小部件的创建。
//源码文件所在位置 packages\widgets\Source\Viewer\Viewer.js
function Viewer(container, options) {
//>>includeStart('debug', pragmas.debug);
if (!defined(container)) {
throw new DeveloperError("container is required.");
}
//>>includeEnd('debug');
container = getElement(container);
...
const that = this;
const viewerContainer = document.createElement("div");
viewerContainer.className = "cesium-viewer";
container.appendChild(viewerContainer);
// Cesium widget container
const cesiumWidgetContainer = document.createElement("div");
cesiumWidgetContainer.className = "cesium-viewer-cesiumWidgetContainer";
viewerContainer.appendChild(cesiumWidgetContainer);
// Bottom container
const bottomContainer = document.createElement("div");
bottomContainer.className = "cesium-viewer-bottom";
viewerContainer.appendChild(bottomContainer);
...
// Info Box
let infoBox;
if (!defined(options.infoBox) || options.infoBox !== false) {
...
}
// Main Toolbar
const toolbar = document.createElement("div");
toolbar.className = "cesium-viewer-toolbar";
viewerContainer.appendChild(toolbar);
// Geocoder
let geocoder;
if (!defined(options.geocoder) || options.geocoder !== false) {
...
}
// HomeButton
let homeButton;
if (!defined(options.homeButton) || options.homeButton !== false) {
...
}
...
let sceneModePicker;
if (
!scene3DOnly &&
(!defined(options.sceneModePicker) || options.sceneModePicker !== false)
) {
sceneModePicker = new SceneModePicker(toolbar, scene);
}
let projectionPicker;
if (options.projectionPicker) {
projectionPicker = new ProjectionPicker(toolbar, scene);
}
// BaseLayerPicker
let baseLayerPicker;
let baseLayerPickerDropDown;
if (createBaseLayerPicker) {
...
}
// These need to be set after the BaseLayerPicker is created in order to take effect
if (defined(options.baseLayer) && options.baseLayer !== false) {
...
}
if (defined(options.terrainProvider)) {
...
}
...
// Navigation Help Button
let navigationHelpButton;
if (
!defined(options.navigationHelpButton) ||
options.navigationHelpButton !== false
) {
...
}
// Animation
let animation;
if (!defined(options.animation) || options.animation !== false) {
...
}
// Timeline
let timeline;
if (!defined(options.timeline) || options.timeline !== false) {
...
}
// Fullscreen
let fullscreenButton;
let fullscreenSubscription;
let fullscreenContainer;
if (
!defined(options.fullscreenButton) ||
options.fullscreenButton !== false
) {
...
}
...
}
初始化各种部件以后,还为场景注册了默认的一些事件,比如单击实体进行选择,双击实体进行视角追踪。
//源码文件所在位置 packages\widgets\Source\Viewer\Viewer.js
function Viewer(container, options) {
...
// Subscribe to left clicks and zoom to the picked object.
function pickAndTrackObject(e) {
...
}
function pickAndSelectObject(e) {
...
}
cesiumWidget.screenSpaceEventHandler.setInputAction(
pickAndSelectObject,
ScreenSpaceEventType.LEFT_CLICK,
);
cesiumWidget.screenSpaceEventHandler.setInputAction(
pickAndTrackObject,
ScreenSpaceEventType.LEFT_DOUBLE_CLICK,
);
}
CesiumWidget 类
大多数情况下,我们会使用new Cesium.Viewer()
作为Cesium应用程序的入口,但是其实new Cesium.CesiumWidget()
也能作为Cesium应用程序的入口,比如我们编写以下代码,也能创建出一个三维应用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cesium高级教程</title>
<script src="https://cesium.com/downloads/cesiumjs/releases/1.122/Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="https://cesium.com/downloads/cesiumjs/releases/1.122/Build/Cesium/Widgets/widgets.css">
<style>
html,
body,
#cesiumContainer {
overflow: hidden;
height: 100%;
width: 100%;
padding: 0px;
margin: 0px;
}
</style>
</head>
<body>
<div id="cesiumContainer"></div>
</body>
<script id="cesiumScript">
let cesiumWidget=new Cesium.CesiumWidget("cesiumContainer");
</script>
</html>
这是因为从部件(组件)的层面上来说,Cesium将其框架内容分为了两大类,分别为渲染引擎部件和页面部件,渲染引擎部件主要就是CesiumWidget
,而页面部件就是页面上的那些小控件,比如时间线、搜索框等,而Viewer
视图容器则是这两种部件的一个容器。
渲染引擎部件主要负责三维场景的渲染,可以独立于页面部件进行使用。而大多数页面部件则依赖于渲染引擎部件,必须在渲染引擎部件初始化后才能创建。当然绝大部分情况下,我们不会选择单独使用渲染引擎部件,因为这只是Cesium框架的一种模块解耦设计,使用完整的框架功能,还是选择使用new Cesium.Viewer()
作为程序入口。
更多内容见 Cesium高级教程-教程简介