Cesium中Entity的渲染流程草图

1.cesium关系草图  

Viewer

    DataSourceDisplay

        DataSourceCollection

        CustomDataSource

            EntityCollection

                Entity

2.

Viewer.entities.add({

    rectangle : {

        coordinates : Cesium.Rectangle.fromDegrees(-92.0, 20.0, -86.0, 27.0),

        outline : true,

        outlineColor : Cesium.Color.WHITE,

        outlineWidth : 4,

        stRotation : Cesium.Math.toRadians(45),

  }

});

当我们调用EntityCollection.add方法时,根据参数会new一个Entity对象,此时EntityCollection充当了一个容器的作用。接着,Cesium内部通过事件的机制,在DataSourceDisplay中根据Entity类型安排具体模块,最终该模块完成对应Entity的解析工作。

3.渲染前DataSourceDisplay就拿到所有的Visualizer(可视化生产器  理解成模子) 

这里添加的是Rectangle所以用到的是GeometryVisualizer:

  DataSourceDisplay.defaultVisualizersCallback =function(scene, entityCluster, dataSource) {

    varentities = dataSource.entities;

    return[

。。。。。
 new GeometryVisualizer(RectangleGeometryUpdater, scene, entities),

。。。。。

];

};

把渲染工作交接给GeometryVisualizer的_onCollectionChanged函数:

entityCollection.collectionChanged.addEventListener(GeometryVisualizer.prototype._onCollectionChanged,this)


加入到对应到队列中排队(这里的队列是_addedEntities)  针对EntityCollection的每一种队列,Visualizer分别提供了_addedObjects,_removedObjects,_changedObjects三个队列一一对接。

EntityCollection.prototype.add =function(entity) {

    if(!(entityinstanceof Entity)) {

        entity =new Entity(entity);

    }

    varid = entity.id;

    if(!this._removedEntities.remove(id)) {

        this._addedEntities.set(id, entity);

    }

    fireChangedEvent(this);

    return entity;

};


总结:DataSourceDisplay初始化的时候会调用defaultVisualizersCallback,会针对所有Geometry的Type创建对应的Visualizer;EntityCollection.Add每次添加一个Entity,会通过一系列事件传递,将该Entity传递到每一个Visualizer,保存到Visualizer中_addedObjects队列中。

Viewer初始化时会绑定clock.onTick事件,确保每一帧都会调用。而其内部则调用DataSourceDisplay.update,进而遍历所有的Visualizer,调用其update方法

GeometryVisualizer.prototype.update做了三件事:

1.new Updater

function RectangleGeometryUpdater(entity, scene) {

    this._options =new GeometryOptions(entity);

    this._onEntityPropertyChanged(entity, 'rectangle', entity.rectangle, undefined);

}


每一个GeometryVisualizer都绑定一个具体的Updater,用来解析Entity,以Rectangle为例// Rectangle则由对应的RectangleGeometryUpdater来解析// 通过new Updater,将Entity对应的RectangleGraphics解析为RectangleGeometryUpdater的GeometryOptionsupdater =newthis._type(entity,this._scene);

        this._updaters.set(id, updater);

        // 根据该RectangleGeometryUpdater的材质风格创建对应的GeometryInstance,分到对应的批次队列中// 每一个批次队列中的Geometry风格相同,因此可以通过一次DrawCommand渲染该队列中所有Geometry// 目的是减少渲染次数,提高渲染效率

2.insertUpdaterIntoBatch

不准确的说(但有助于理解),GeometryOptions主要对应RectangleGraphics的几何数值,而在insertUpdaterIntoBatch中则根据RectangleGraphics的材质风格进行分组,只有材质一致的RectangleGeometryUpdater才能分到一起,进行后面的批次。比如学校分班,优等生,中等生分到不同的班级,老师根据不同班级的能力进行适当的区分,就是一种通过分组的方式来优化的思路。打组批次也是同样一个道理。

3.batch.update

       之前的步骤1和步骤2,我们对当前这一帧中新增的Entity进行解析,构造成对应的GeometryInstance,放到对应的Batch队列中。比如有两个Rectangle类型的Entity,假设他们的风格一样,都是纯色的,当然颜色可能不相同,但最终都是在一个批次队列(StaticOutlineGeometryBatch)。接下来,1每一个批次队列会构建一个Primitive,包括该队列中所有的GeometryInstances,因为显卡强大的并行能力,绘制一个三角面和绘制N个三角面的所需的时间是一样的(N取决于顶点数),2所以尽可能的将多个Geometry封装成一个VBO是提高渲染性能的一个关键思路(批次&实例化)。而这个batch.update完成的前半部分,而Primitive.update则完成了最后,也是最关键的一步。


总结上面大致流程:

DataSourceDisplay.prototype.update

    GeometryVisualizer.prototype.update

        updater =newthis._type(entity,this._scene);

            new GeometryOptions(entity);

            _onEntityPropertyChanged()


        insertUpdaterIntoBatch

            StaticGeometryColorBatch.prototype.add

                RectangleGeometryUpdater.prototype.createFillGeometryInstance

                    new GeometryInstance()

                Batch.prototype.add


        batches[i].update(time)

            StaticGeometryColorBatch.prototype.update

                Batch.prototype.update

                    new Primitive()

                    primitives.add(primitive);


Primitive.prototype.update

this._scene.render(currentTime);

    Scene.prototype.render

        function render(scene, time)

            function updateAndExecuteCommands()

                function executeCommandsInViewport()

                    function updatePrimitives()

                        PrimitiveCollection.prototype.update()

                            for (var i = 0; i < primitives.length; ++i) {

                                primitives[i].update(frameState);

                            }


loadAsynchronous(多线程创建vbo),createVertexArray以及create*这几个内容

createVertexArray

上面的Geometry已经将数据处理为indexBuffer和vertexBuffer,下面则需要将该数据结合attributes创建为vbo&vao,这个过程就是通过createVertexArray完成

createRS

创建RenderState

createSP

创建ShaderProgram

       很明显,渲染主要是数据+风格,当我们满足了geometry的数据部分已经符合WebGL渲染的格式后,结合appearance封装的材质,设置对应的RenderState以及Shader和所需要的参数。最后,我们构造出最终的DrawCommand,添加到DrawCommandList中,完成最终的渲染

你可能感兴趣的:(Cesium中Entity的渲染流程草图)