作者:taco
前言:
上一篇介绍了以一个新手如何去初始化地球。这一篇我们将慢慢的深入进去。但暂时还不去真正的添加数据去展示,而是来研究一下。初始化的过程中我们都干了些什么?自主客户端中,和以往的Cesium不太一样。cesium中只需要 var viewer = new Cesium.Viewer('cesiumContainer')即可完成项目的初始化。而自主客户端中则是使用initGlobe("Container");用来初始化地球。很明显,在initGlobe中,我们完成了许多操作,这篇文章就来看看init中都做了什么操作?
initGlobe.js
我们来逐行分析一下,首先第一步就是定义变量
const {
Scene,
Globe,
Cartesian3,
Ellipsoid,
SingleTileImageryProvider
} = SuperMap3D;
熟悉es6语法的话,可能就不用过多去解释这个是如何去定义变量的了。不过这里多嘴补充一下。上面代码相当于
const Scene = SuperMap3D.Scene; //场景(Scene)
const Globe = SuperMap3D.Globe; //场景中渲染的地球(Globe)
const Cartesian3 = SuperMap3D.Cartesian3; //三维笛卡尔坐标(Cartesian3)
const Ellipsoid = SuperMap3D.Ellipsoid; //椭球体(Ellipsoid)
const SingleTileImageryProvider = SuperMap3D.SingleTileImageryProvider; //底图单张图片影像(SingleTileImageryProvider)
接着中间一大段都是创建节点以及创建画布,在后续实际使用的过程并不会有过多影响。这里就忽略不去说明了。
// 根据id为container 属性获取节点对象
container = document.getElementById(container);
//创建一个子对象
var element = document.createElement('div');
//widget
element.className = 'widget';
//子节点列表末添加element子节点
container.appendChild(element);
//创建一个画布作为子节点
var canvas = document.createElement('canvas');
//oncontextmenu 事件在元素中用户右击鼠标时触发并打开上下文菜单。
canvas.oncontextmenu = function() {
return false;
};
//Firefox/Opera不支持onselectstart事件
// onselectstart 事件是用来实现元素内文本不被选中
canvas.onselectstart = function() {
return false;
};
子节点列表末添加canvas子节点
element.appendChild(canvas);
于是来到了正题,使用上面创建的画布来初始化场景。
scene = new Scene({
canvas: canvas
});
接下来的参数
scene.pixelRatio = 1;
这个参数与cesium中viewer.resolutionScale,有一些类似,目的是为了解决锯齿和页面模糊的问题。要使得这个值与window.devicePixelRatio的值相等,而devicePixelRatio的属性指的是当前显示设备的物理像素分辨率与css像素分辨率的一个比率,也就是css/物理像素的大小的比值。常规来说这个值都是1,但是如果实际比值(电脑原因如mac的比值可能就是1.25)大于这个值的话就要去更改我们的pixelRatio,使得这个值等于我们屏幕的比值.。当然我们也可以去修改代码,直接去判断一下我们当前的值,然后赋给scene.pixelRatio也是可以的。
scene.camera.constrainedAxis = Cartesian3.UNIT_Z;
constrainedAxis官方的范围指的是约束轴,相机无法在任意方向上旋转超过此轴。其实就是固定轴。当视角到这个轴的位置时,只能根据这个轴去旋转,不能跨过这个轴。但是常规这个值都会设置为UNIT_Z或者undefined。
configureCameraFrustum();
function configureCameraFrustum() {
var width = canvas.width;
var height = canvas.height;
if (width !== 0 && height !== 0) {
var frustum = scene.camera.frustum;
if (frustum.aspectRatio) {
frustum.aspectRatio = width / height;
} else {
frustum.top = frustum.right * (height / width);
frustum.bottom = -frustum.top;
}
}
}
初始化相机视锥体,改怎么描述这个参数呢?很有意思的一个现象。实际的视锥体是根据浏览器像素的长宽比来进行调整的。让我缩小我的浏览器数值就会变小,其实也很好理解是我的width变小了,但是但是高度并没有给他改动多少。frustum.aspectRatio 当我去故意改变这个值的时候,有趣的事情就会发生。我们给他乘了个10。相对原来的基础上就会向中间夹紧。也就是说值越大球越瘪。 具体的视锥体的构建,之前见过有一篇文章写过相关内容可以参考一下。
说完视锥体我们继续看初始化。
scene.globe = new Globe(Ellipsoid.WGS84);
scene.sun = new SuperMap3D.Sun();
scene.skyAtmosphere = new SuperMap3D.SkyAtmosphere();
很显然这里将地球初始化为WGS84坐标系的地球。就目前来说是支持WGS84坐标系的,后续是否会出现支持的其他坐标系,或者使用其他坐标系来初始化还是未知的。这个后面如果有追加的话再进行补充。后面两句也是很好理解的,其中一个是阳光,另一个是大气
层。
requestAnimationFrame(render);
requestAnimationFrame是浏览器用于定时循环的接口,按帧对网页进行重绘。 可以理解为settimeout()的方法。不过这个接口更好的利用了显示器的刷新机制(刷新率60Hz或75Hz)把每一帧中的所有DOM操作集中起来,每秒钟重绘60次或75次。在隐藏或不可见的元素中,requestAnimationFrame则将不会进行重绘,节省了gpu,cpu的消耗。
这样我们就跟着requestAnimationFrame进入render
function render() {
resize();
scene.initializeFrame();
scene.render();
requestAnimationFrame(render);
}
第一部分resize
function resize() {
var width = canvas.clientWidth;
var height = canvas.clientHeight;
if (curCanvasClientWidth === width && curCanvasClientHeight === height && lastDevicePixelRatio === window
.devicePixelRatio) {
return;
}
configureCanvasSize();
configureCameraFrustum();
}
在resize的过程中,主要还是去判断当前浏览器的大小去调整画布的大小以及视锥体的大小。如果本身浏览器的大小没有变化,则是没有任何影响。如果我浏览器变大或变小。则会去执行下面两个的function。
function configureCanvasSize() {
var width = canvas.clientWidth;
var height = canvas.clientHeight;
var pixelRatio = configurePixelRatio();
curCanvasClientWidth = width;
curCanvasClientHeight = height;
width *= pixelRatio;
height *= pixelRatio;
var maxDrawingBufferWidth = 3840;
var maxDrawingBufferHeight = 1080;
var newWidthHeight = computeWidthHeight(width, height, maxDrawingBufferWidth, maxDrawingBufferHeight);
canvas.width = newWidthHeight.width;
canvas.height = newWidthHeight.height;
lastDevicePixelRatio = window.devicePixelRatio;
}
其实和最上面介绍的是一致的是一个画布像素的问题以及视锥体。只不过是这里多出了maxDrawingBufferWidth和maxDrawingBufferHeight这两个参数。先看一下效果,如果我将宽设置为150,高设置为200。
正常的是下面这张图。
这里可以理解为分辨率,正常来说设置成当前电脑分辨率即可,但是如果屏幕使用的是125%或是150%则需要去算一下再去设置。不过适当增大并不会太影像到清晰度,但是如果过小的话,地球可是会虚的。
在前期所有的基础都做好后,最后终于开始去渲染我们的场景了。这里直接调用了这两个方法,具体内容还是封装起来的了。有兴趣的朋友们可以看一下原生cesium的渲染机制来了解一下这一步具体都干了些什么。
scene.initializeFrame();
scene.render();
在最后留下一些写的超级好的文档以便查阅