翻譯有誤請指出,規範性轉載。@秋意正寒。api
原文出處Graphics Tech in Cesium - Renderer Architecture | cesium.com數組
Cesium 是一個 WebGL 引擎,自 WebGL 1.0 在 2011 年 3 月發佈後,官方就開始開發了。緩存
官方將 Cesium 的 Renderer 視爲他們本身的第四代渲染器,由於它基於他們的 OpenGlobe 的經驗改進而來。除此以外,還有其餘技術人員在 AGI 的 Insight 3D 和 STK 的經驗。因此說,Cesium 的渲染器並非憑空設計而來。框架
固然,能夠把 WebGL 的調度分散在各處,可是集中在一個渲染器對象中有不少好處:函數
推出 Cesium 的渲染器的主要緣由是官方有豐富的經驗,而且能夠根據實際狀況調整 Cesium 引擎以得到最佳性能。性能
Cesium 的着色器流水線遠遠超出了普通圖形程序的概念範圍。學習
還有一個緣由是由於,官方推出這個實際上是想經過此學習 JavaScript,並且 WebGL 在 2011 年的時候並不成熟(發文時是 2015年)。ui
在 Cesium 1.9 中,渲染器的主要組件(js對象)是:編碼
VertexArray、RenderState、ShaderProgram、FrameBufferprototype
Renderer 類在 Source/Renderer
目錄下。Renderer 的代碼並非公開的 api,因此謹慎使用。
左邊一列的對象構成 Cesium 的繪製命令的基礎,它們封裝了 WebGL 的 drawcall 指令。爲了渲染一幀,Cesium 在隨處都會執行這些命令。
Buffer
對象中(參考 Buffer.js)。若是可行,頂點數組使用 OES_vertex_array_object
的擴展名以減小 WebGL 的調用次數(這句不太懂)。着色器保存在 Source/Shader
目錄下的 .glsl
後綴名的文件中。
Cesium 會刪除文件內的註釋、無效空格,並轉換爲 js 代碼(字符串)以便其餘 Cesium 對象能調用,而無需從新請求文件。
Cesium 提供了一個龐大的 GLSL 函數庫,包括函數、結構體、常量。若是你的代碼須要用到自定義 glsl 代碼,你徹底能夠不聲明、不加入 #include
預編譯指令,能夠直接使用它們。
它們以 czm_
開頭標識。例如,這是一個天空大氣的片元着色器:
czm_ellipsoid ellipsoid = czm_getWgs84EllipsoidEC(); vec3 direction = normalize(v_positionEC); czm_ray ray = czm_ray(vec3(0.0), direction); czm_raySegment intersection = czm_rayEllipsoidIntersectionInterval(ray, ellipsoid); if (!czm_isEmpty(intersection)) { discard; }
這些內置對象造成了有向無環圖(DAG)。
在運行時,glsl 源代碼將傳遞給 ShaderSource
對象,這個對象查找 czm_
字符串並遍歷 DAG
以生成最終的着色器。
若是在拾取操做時用到了着色器,它還會輸出 pick id,而不是真正的顏色(這句話沒看太懂)。
以上均在 Cesium 程序運行的時候完成的,而不是寫死在引擎內部。由於有的繪製直到它要進行繪製時才知道着色器的編碼順序等。
內置的 GLSL uniform 被稱爲 自動 uniform。它也不須要聲明或引入 #include,遍歷 DAG 會同樣遍歷到。
自動 uniform 一般表明與幀相關(或視錐體相關、命令相關)的值,例如變換矩陣。見 AutomaticUniforms.js
。
例如,天空盒的頂點着色器使用到了自動 uniform 來轉換一個 2x2x2 的立方體的座標,這個立方體的中心在 True Equator Mean Equinox 框架,轉換到裁剪座標的中心:
attribute vec3 position; varying vec3 v_texCoord; void main() { vec3 p = czm_viewRotation * (czm_temeToPseudoFixed * (czm_entireFrustum.y * position)); gl_Position = czm_projection * vec4(p, 1.0); v_texCoord = position.xyz; }
使用原始的 GLSL 源代碼做爲 key 來緩存着色器程序,以減小初始化和使用着色器時的 WebGL 調用數。參考 ShaderCache.js
。
熟悉 WebGL 的讀者,應該知道繪製命令的執行是由 WebGLContext
對象的 drawXXX
函數執行的。它被封裝在 Cesium 的 Context.prototype.draw
方法中,它作了這些事:
當一幀結束後,Context.prototype.endFrame
方法會解除着色器的 WebGLProgram 的綁定、解除對幀緩存、繪製緩存、紋理的綁定以清理狀態。這樣能減小每一個繪製命令執行時渲染器的狀態管理量。
渲染器將被 Scene 對象給 Primitive 對象來建立 WebGL 資源。例如,Globe 自己和三維模型。而且,渲染器還將執行繪製命令,將這些資源繪製到一幀上。
WebGL 2.0 的出現,須要對渲染器進行不少改進。
與時下不少引擎同樣,設置 uniform 變量是 Cesium 的瓶頸。Uniform buffers 在 WebGL 2 獲得了性能上的提升。
支持實例的繪製使得 Cesium 能渲染大量對象,例如樹,固然每棵樹能夠有不一樣的屬性,例如位置、高度等。
感謝 Greg Beatty 和 Scott Hunter,他們編寫了 glsl 着色器。
[Cozzi11] Patrick Cozzi and Kevin Ring. 3D Engine Design for Virtual Globes. CRC Press. 2011.