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中,完成最終的渲染