tft每日頭條

 > 生活

 > cesium怎麼學

cesium怎麼學

生活 更新时间:2024-10-13 09:03:48

Cesium 第一幀渲染指南

Cesium作為開源地圖三維可視化的巨擘,在行業内有着廣泛的應用。這裡先不讨論内部實現原理,僅就渲染流程做個分析。

1 Viewer

下面一句話,就可以創建出一個默認的地球

var viewer = new Cesium.Viewer("cesiumContainer");

如下圖所示,不僅有地球,還有右上角的工具欄,左下角的一個時鐘,底部的一個文字标簽和時間軸等小部件。這些都是如何呈現出來的呢,現在就進入到new Viewer() 内部看看。

cesium怎麼學(第一幀渲染指南)1

function Viewer(container, options) { //... var that = this; Util.log("創建div容器viewerContainer,添加到map的div容器中"); var viewerContainer = document.createElement("div"); viewerContainer.className = "cesium-viewer"; container.appendChild(viewerContainer); // Cesium widget container Util.log("創建div容器cesiumWidgetContainer,添加到viewerContainer的div容器中") var cesiumWidgetContainer = document.createElement("div"); cesiumWidgetContainer.className = "cesium-viewer-cesiumWidgetContainer"; viewerContainer.appendChild(cesiumWidgetContainer); // Bottom container Util.log("創建bottomContainer的div容器添加到viewerContainer"); var bottomContainer = document.createElement("div"); bottomContainer.className = "cesium-viewer-bottom"; viewerContainer.appendChild(bottomContainer); //... //系統時鐘 Util.log('創建Clock時間系統'); var clock; var clockViewModel; var destroyClockViewModel = false; if (defined(options.clockViewModel)) { clockViewModel = options.clockViewModel; clock = clockViewModel.clock; } else { clock = new Clock(); clockViewModel = new ClockViewModel(clock); destroyClockViewModel = true; } if (defined(options.shouldAnimate)) { clock.shouldAnimate = options.shouldAnimate; } // Cesium widget Util.log("\n CesiumWidget構造函數,初始化各種小部件,比如天空和skybox,圖層的provider等\n 這裡有個useDefaultRenderLoop布爾類型選項,默認為true,如果為false,則不會調用Viewer.render,就無法\n 循環渲染每一幀,隻會渲染第一幀\n "); var cesiumWidget = new CesiumWidget(cesiumWidgetContainer, { imageryProvider: createBaseLayerPicker || defined(options.imageryProvider) ? false : undefined, clock: clock, skyBox: options.skyBox, skyAtmosphere: options.skyAtmosphere, sceneMode: options.sceneMode, 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, terrainExaggeration: options.terrainExaggeration, shadows: options.shadows, terrainShadows: options.terrainShadows, mapMode2D: options.mapMode2D, requestRenderMode: options.requestRenderMode, maximumRenderTimeChange: options.maximumRenderTimeChange, }); Util.log('工具小組件: '); Util.logObj(cesiumWidget); Util.log("創建dataSource集合dataSourceCollection"); var dataSourceCollection = options.dataSources; var destroyDataSourceCollection = false; if (!defined(dataSourceCollection)) { dataSourceCollection = new DataSourceCollection(); destroyDataSourceCollection = true; } var scene = cesiumWidget.scene; //... }

從代碼中可以看到,首先創建了幾個div容器,用來存放地球上的小部件。接着創建了一個Clock時鐘。時鐘創建之後,實例化了一個非常重要的變量 cesiumWidget,從代碼中可以看到,cesiumWidget 的實例化中有很多參數,其中就包含上一步創建的 Clock 時鐘。注意實例化 cesiumWidget 之後,會将其上面挂載的scene賦值給viewer裡面的 scene。接着,我們進入到 cesiumWidget 中看實例化過程中都執行了什麼。

2 CesiumWidget

function CesiumWidget(container, options) { //... Util.log("創建canvas"); var canvas = document.createElement("canvas"); try { //地球也是一個widget,創建一個場景 var scene = new Scene({ canvas: canvas, contextOptions: options.contextOptions, creditContainer: innerCreditContainer, creditViewport: creditViewport, mapProjection: options.mapProjection, orderIndependentTranslucency: options.orderIndependentTranslucency, scene3DOnly: defaultValue(options.scene3DOnly, false), terrainExaggeration: options.terrainExaggeration, shadows: options.shadows, mapMode2D: options.mapMode2D, requestRenderMode: options.requestRenderMode, maximumRenderTimeChange: options.maximumRenderTimeChange, }); this._scene = scene; //... var globe = options.globe; if (!defined(globe)) { globe = new Globe(ellipsoid); } if (globe !== false) { scene.globe = globe; scene.globe.shadows = defaultValue( options.terrainShadows, ShadowMode.RECEIVE_ONLY ); } //... var skyBox = options.skyBox; this._useDefaultRenderLoop = undefined; //設置useDefaultRenderLoop Util.log("設置useDefaultRenderLoop,Cesium裡面對useDefaultRenderLoop進行了劫持,在setter裡面調用了渲染函數"); // debugger this.useDefaultRenderLoop = defaultValue( options.useDefaultRenderLoop, true ); //... } catch (error) { //... } }

可以看到,在cesiumWidget中創建了一個canvas,就是在這個canvas上面使用webgl繪制三維球的。接着又實例化了一個Scene,也就是創建了一個場景。注意在cesiumWidget中創建了地球相關的部件,比如天空盒,晨昏線,大氣層等。還有一個至關重要的參數useDefaultRenderLoop,再往下翻,可以看到這個參數是做了數據劫持的:

useDefaultRenderLoop: { get: function () { return this._useDefaultRenderLoop; }, set: function (value) { if (this._useDefaultRenderLoop !== value) { this._useDefaultRenderLoop = value; if (value && !this._renderLoopRunning) { Util.log("在設置useDefaultRenderLoop的時候啟動渲染"); startRenderLoop(this); } } }, },

用來判斷是否對第一幀之後的每一幀進行渲染。如果設置且為true,則渲染,否則不渲染。

進入到實例化Scene的構造函數中來。

3 Scene

function Scene(options) { Util.log("創建Scene的初始選項: "); //根據GPU性能選擇适合的渲染上下文渲染狀态。可以是"high-performance", "low-power" 或者 "default"。默認為 "default"。 contextOptions.webgl.powerPreference = defaultValue( contextOptions.webgl.powerPreference, "high-performance" ); //... //>>includeEnd('debug'); var hasCreditContainer = defined(creditContainer); var context = new Context(canvas, contextOptions); this._jobScheduler = new JobScheduler(); this._frameState = new FrameState( context, new CreditDisplay(creditContainer, " • ", creditViewport), this._jobScheduler ); //... this._FrameState.scene3DOnly = defaultValue(options.scene3DOnly, false); this._removeCreditContainer = !hasCreditContainer; this._creditContainer = creditContainer; this._canvas = canvas; this._context = context; this._computeEngine = new ComputeEngine(context); this._globe = undefined; this._globeTranslucencyState = new GlobeTranslucencyState(); Util.log("創建PrimitiveCollection"); this._primitives = new PrimitiveCollection(); this._groundPrimitives = new PrimitiveCollection(); //... Util.log("創建事件,_preUpdate,_postUpdate,_renderError,_preRender,_postRender"); this._preUpdate = new Event(); this._postUpdate = new Event(); this._renderError = new Event(); this._preRender = new Event(); this._postRender = new Event(); //... updateFrameNumber(this, 0.0, JulianDate.now()); this.updateFrameState(); this.initializeFrame(); }

Scene中多是和webgl相關的。主要看最後三個函數,第一個函數updateFrameNumber更新幀數,第二個參數就是第幾幀,很明顯這裡是第1幀,第二和第三個函數 this.updateFrameState(); this.initializeFrame();,就是對第一幀的渲染。

至此Scene實例化完成,回到cesiumWidget中去,緊接着在cesiumWidget中完成了地球的創建等。cesiumWidget實例化完成,回到Viewer中去,此時Viewer實例化完畢,整個地球也就創建好了。

總的來說,整個渲染過程主要的三個實例化:

  • Viewer的實例化。
  • 在Viewer的實例化中完成cesiumWidget的實例化。
  • 在cesiumWidget的實例化中完成Scene的實例化。
,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved