Cesium渲染机制概览

Cesium基于WebGL实现,所以渲染机制跟我们直接用WebGL的道理相同,但是内部功能强大,会更复杂些
目前不讨论Cesium的实现原理,先了解下Cesium的大体渲染流程的机制,有个初步认识

HelloWorld

亘古不变的HelloWorld,一句代码就可以绘制出来地球和很多小部件

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

来一层一层看下地球是如何出来的
Viewer.js 相关代码

    function Viewer(container, options) { 
      container = getElement(container);
      options = defaultValue(options, defaultValue.EMPTY_OBJECT);
      
      var viewerContainer = document.createElement("div");
      viewerContainer.className = "cesium-viewer";
      container.appendChild(viewerContainer);

      // Cesium widget container
      var cesiumWidgetContainer = document.createElement("div"); 
      viewerContainer.appendChild(cesiumWidgetContainer);

      // Bottom container
      var bottomContainer = document.createElement("div");  
      viewerContainer.appendChild(bottomContainer); 

      // Cesium widget
      var cesiumWidget = new CesiumWidget(cesiumWidgetContainer, {
        imageryProvider: imageryProvider,
        // ...
        sceneMode: options.sceneMode, 
      });
           
      // ...
      // 初始化具体小部件、属性、事件等
    }

Viewer()方法作为入口,构建必须的dom元素,初始化具体小部件、属性、事件等,很重要的一个就是实例化了CesiumWidget,而CesiumWidget内部构建了定时器,用来不断刷新并渲染页面
CesiumWidget.js 相关代码

// 定义定时器
    function startRenderLoop(widget) {
      var lastFrameTime = 0;
      function render(frameTime) {
        // ...
        widget.resize();
        widget.render();
        requestAnimationFrame(render);
        // ...
      }
      requestAnimationFrame(render);
    }

    function CesiumWidget(container, options) {
      container = getElement(container);

      //Configure the widget DOM elements
      var element = document.createElement("div");
      element.className = "cesium-widget";
      container.appendChild(element);

      var canvas = document.createElement("canvas");
      canvas.addEventListener("mousedown", blurActiveElement);
      canvas.addEventListener("pointerdown", blurActiveElement);

      element.appendChild(canvas);

      var scene = new Scene({
        canvas: canvas,
        // ...
      });
      this._scene = scene;

      var ellipsoid = defaultValue(
        scene.mapProjection.ellipsoid,
        Ellipsoid.WGS84
      );

      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;
      var skyAtmosphere = options.skyAtmosphere;
      var imageryProvider = createWorldImagery();
      scene.terrainProvider = options.terrainProvider;

      // 给 useDefaultRenderLoop 属性赋值,触发了
      this._useDefaultRenderLoop = undefined;
      this.useDefaultRenderLoop = defaultValue(
        options.useDefaultRenderLoop,
        true
      );

    }

    Object.defineProperties(CesiumWidget.prototype, {
      // ...
      // 通过set设置在赋值时,触发定时器
      useDefaultRenderLoop: {
        get: function () {
          return this._useDefaultRenderLoop;
        },
        set: function (value) {
          if (this._useDefaultRenderLoop !== value) {
            this._useDefaultRenderLoop = value;
            if (value && !this._renderLoopRunning) {
              startRenderLoop(this);
            }
          }
        },
      }
    })

    // render方法
    CesiumWidget.prototype.render = function () {
      if (this._canRender) {
        this._scene.initializeFrame();
        var currentTime = this._clock.tick();
        // 此时调用_scene的渲染方法
        this._scene.render(currentTime);
      } else {
        this._clock.tick();
      }
    };

this._scene.render(currentTime)执行时,会调用scene的渲染方法,来渲染场景中的各类要素
Scene.js 相关代码

    function render(scene) {
      // ...
      // globe地球渲染开始
      scene.globe.beginFrame(frameState);
      // 其它环境、覆盖物渲染等
      scene.updateEnvironment();
      scene.updateAndExecuteCommands(passState, backgroundColor);
      scene.resolveFramebuffers(passState);
      executeOverlayCommands(scene, passState);
      // globe地球渲染结束
      scene.globe.endFrame(frameState);

    }

    Scene.prototype.render = function (time) { 
      tryAndCatchError(this, prePassesUpdate); 
      tryAndCatchError(this, updateMostDetailedRayPicks);
      tryAndCatchError(this, updatePreloadPass);
      tryAndCatchError(this, updatePreloadFlightPass);
      // 调用render()
      tryAndCatchError(this, render); 
    };

此处就可以看到globe的渲染方法登场,地球的绘制是通过地形和地图叠加到椭球体显示而成
Globe.js 相关代码

    function Globe(ellipsoid) {
      ellipsoid = defaultValue(ellipsoid, Ellipsoid.WGS84);
      var terrainProvider = new EllipsoidTerrainProvider({
        ellipsoid: ellipsoid,
      });
      var imageryLayerCollection = new ImageryLayerCollection();

      this._ellipsoid = ellipsoid;
      this._imageryLayerCollection = imageryLayerCollection;

      this._surfaceShaderSet = new GlobeSurfaceShaderSet();
      this._material = undefined;

      this._surface = new QuadtreePrimitive({
        tileProvider: new GlobeSurfaceTileProvider({
          terrainProvider: terrainProvider,
          imageryLayers: imageryLayerCollection,
          surfaceShaderSet: this._surfaceShaderSet,
        }),
      });
      // ...
    }

    Globe.prototype.beginFrame = function (frameState) {
      var surface = this._surface;
      var tileProvider = surface.tileProvider;
      var terrainProvider = this.terrainProvider;
      var hasWaterMask = this.showWaterEffect
      // ...
      surface.tileCacheSize = this.tileCacheSize;
      tileProvider.terrainProvider = this.terrainProvider;
      tileProvider.hasWaterMask = hasWaterMask;
      surface.beginFrame(frameState); 
      // ...
    }; 

地球表面包含着地形、切片、水面等,统一由tileProvider处理,通过surface.beginFrame(frameState)执行
由此,能看到各级关系如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章