GPU:以前用cpu來做渲染,但cpu是串行架構的,這樣就會導致渲染效率很低,后來就發明了gpu,gpu是並行計算的,同時處理多任務。衡量gpu性能的一個重要術語叫 每秒像素填充率。
oepngl es:一套圖形硬件的軟件接口,直接和gpu交互,多應用於各類嵌入和手持平台
OpenGL ES 2.0渲染管線
左邊為客戶端,右邊為opengl服務端。客戶端將頂點,着色器程序,紋理和其他gl狀態傳入服務端,然后客戶端調用繪制命令,gl就對輸入的圖元執行一系列處理,把結果的像素填入到幀緩沖,交換緩沖區就顯示在屏幕上。
過程中,頂點着色器和片段着色器是可編程的,程序可通過提供着色器程序達到在gpu中渲染管線的目的。其他階段只能用一些固定的gl命令來影響該階段的執行
頂點數組
傳入opengl es前,,3d模型會轉為一組圖元的集合。每個圖元都是一個點,線段或者三角形(或者多邊形),模型間獨立繪制,修改模型的某些設置不會影響其他模型的繪制。
圖元都是由一個或多個頂點組成,組成線段或者三角形,每個點都關聯着數據,包括坐標,顏色,法向量和紋理坐標。
通過綁定頂點緩沖對象(vertex buffer objects,vbo),把頂點數組數據傳入到渲染管線。
opengl中命令按接受順序執行,所以一組圖元繪制完畢才會繪制下一組。
頂點着色器
頂點着色器是一段類似c的程序,由程序員提供在gpu執行,對頂點運算。可計算頂點的坐標,顏色,光照,紋理坐標。
着色器最重要的任務就是頂點坐標轉換,即游戲的坐標系轉為opengl的坐標系,這里就執行模型視圖變換,轉為裁剪坐標系,頂點着色器轉換后的坐標存於gl_Postion。
着色器另一個功能是向后面片段着色器提供一組易變變量,用於圖元裝配階段后的插值計算,具體后續補充。
圖元裝配
頂點數組進入gl渲染管線時,頂點坐標位於應用程序的本地坐標系,着色器計算后轉為裁剪坐標系,通常是向頂點着色器傳入一個模型視圖變換矩陣,執行坐標變換實現。
裁剪坐標系定義在一個視錐體里,這是游戲的可視空間,由6個面組成,如下圖。
圖元如果和任意面相交,會觸發裁剪,產生新圖元。透視裁剪需要每個圖元和6個面進行相交計算並產生新圖元,影響性能。如果在x或y方向上超出屏幕(glViewport定義)部分,則不用產生新圖元,在視口變換時候高效丟棄。
視錐體在3d游戲里通常表現為一個攝像機,觀察點為原點,可通過gluPerspective定義其結構(開口大小,平面尺寸等),gluLookAt定義觀察點。
視錐體遠近平面比例應該保持一致,否則轉為屏幕時會導致圖元變形。
視錐體裁剪后需要透視分離,投影到視口上,稱為規則化的設備坐標系,取值[0,1]。最后規則化后的坐標經過視口變換轉為屏幕坐標,視口位置和尺寸通過void glViewPort(Glintx, Glint y, GLsizei w, GLsizei h)定義,左下角起點,單位都是像素。
光柵化
在光柵化之前,要判斷圖元是面對觀察者還是背對觀察者,以決定是否丟棄圖元,glFrontFace命令來決定哪個反方向為正,glCUllFace命令決定保留哪個方。這樣做減少不必要的繪制。方向的確定主要通過頂點的索引,索引都是按順序的,可通過順序的方向來決定。
光柵化會對圖元的片段采樣,以決定哪些片段位於圖元內。過程中,片段坐標值是離散的正數,丟失精度,可能出現鋸齒。
而后,片段着色器就能使用這坐標值對該片段進行着色,最終化為一個像素。光柵化中還要計算頂點着色器定義的易變變量的插值,給后面的片段着色器做插值使用。
片段着色器
這是可編程的,可實現高級特效,如貼圖,光照,環境光,陰影等。其作用主要是計算每一個片段的顏色值。
片段着色器根據頂點着色器輸出的頂點紋理坐標對紋理采樣,計算該片段顏色,最后寫入幀緩沖。實際上還有放大縮小等問題,一般可通過glTexParameter設置一些處理方式,例如多級紋理。
片段着色器可執行光照等高級特效的地方,例如傳入光照位置和光源顏色,經過一定公式計算得出新顏色,就有光照效果了。
片段測試
像素所有權:像素位置所有權是否屬於OpenGL Es,例如被其他窗口擋住了
裁剪測試:glScissor設定一個矩形,在區域外的都被丟棄
多重采樣片段操作:就通過某種采樣方式來計算顏色
深度測試:貌似3d里的概念,3d里存在遠近,近的覆蓋遠的,所以需要一個深度測試,放棄一些像素點的繪制
模版測試:通過預設的條件,一般為mask值,如果通過條件則通過測試,否則丟棄,具體應用有ClippingNode
混合:描述圖片和場景當前位置的顏色組合
完成片段測試后,就能寫入幀緩存區了,然后顯示。
渲染管線中的並行計算
opengl es是按順序執行命令,但每一個階段都是並行的,而階段內部被拆分成多個子任務,也是並行的,也就是縱向橫向都並行。正因為如此,所以計算需要的數據都得依賴於傳入和狀態的設定。opengl es是一個狀態機,很多操作都依賴當前特定狀態值,這樣做能保證並行計算,提高渲染效率
構建高性能渲染引擎
減少渲染次數(draw call):主要是每一次draw call都會伴隨着數組和紋理的復制(cpu->gpu),紋理的復制是十分耗的,減少調用能減少這些復制,可以在一次調用中傳遞更多的頂點數組,使用同一張紋理的操作盡量合並。cocos2dx提供的紋理batch類就是做相似的工作
渲染從主線程分離:利用cpu多線程的優勢,避免cpu和gpu速度差異帶來對性能的影響。繪制命令集中可方面優化。但cocos2dx是單線程,但繪制邏輯已經從ui樹中抽離,做成了單獨的command,后面會說。
幀緩沖
渲染管道最后目的就是將每個像素點的顏色,深度,模版等數據傳送到幀緩沖區。
幀緩沖區存儲着所有像素點的顏色深度和模版值,一個幀緩沖對應3個附加點,組成一個邏輯緩沖區,分別存顏色,深度和模版數據。每個附加點綁定到一個渲染緩沖對象。顏色和深度附加點可以綁定到一個紋理上,就可以繪制到紋理而不是顯示設備了。
視窗系統提供幀緩沖,可多個,切換不需要切換opengl es上下文。
內容繪制到視圖幀緩沖才會顯示在屏幕,一般采用雙緩沖區,一個顯示,一個后台繪制,繪制完切換到前台顯示,達到流暢顯示的效果。