- 注:這篇文集是針對《OpenGL ES應用開發(fā)實踐指南 iOS卷》的學習筆記。
- 后續(xù)會根據(jù)學習進度不斷更新OpenGL ES案例解讀,當然會有自己的理解。
- 筆者也是0基礎開始學習OpenGL ES,有大牛發(fā)現(xiàn)文中有誤的希望能在評論中指出,也歡迎OpenGL ES新手一起探討學習。
圖形渲染原理及問題
- 圖像顯示過程:把程序提供的幾何數(shù)據(jù)轉換為屏幕上的圖像的過程叫做渲染。CUP處理圖形數(shù)據(jù)->傳遞給GPU->GPU渲染圖形數(shù)據(jù)為2D的平面圖像顯示到屏幕。
- 使用現(xiàn)代硬件渲染3D圖形的速度幾乎完全取決于不同的內存區(qū)域被訪問的方式。
- 從內存的一個區(qū)域將數(shù)據(jù)拷貝到另一個區(qū)域是相對較慢的,更糟糕的是,除非非常小心,在內存復制發(fā)生的時候GPU和CPU都不能把內存另作他用。因此內存區(qū)域之間的數(shù)據(jù)交換需要盡量避免。
- 所有的內存訪問都是相對較慢的。CPU大約每秒一億次運算,但只能每秒讀寫內存200萬次,GPU理想狀態(tài)下每秒執(zhí)行數(shù)億次運算,但是卻只能每秒訪問內存2億次。GPU和CPU總是處于“數(shù)據(jù)饑餓”狀態(tài)。
- 概括最新OpenGL ES和以前的OpenGL版本之間的差異的一種方式是:最新的為了支持新改進的方法拋棄了舊式的低效內存復制操作的支持。
緩存:提供數(shù)據(jù)的最好方式
OpenGL ES為兩個內存區(qū)域間的數(shù)據(jù)交換定義了緩存(buffers)概念。即圖形處理器能夠控制和管理連續(xù)的RAM。緩存的概念解決了上面3中的問題。幾乎所有的程序提供給GPU的數(shù)據(jù)都應該放入緩存中。
- 為緩存提供數(shù)據(jù)有如下7個步驟:
- ①生成(Generate)
C函數(shù):glGenBuffers()
—— 請求OpenGL ES為圖形處理器控制的緩存生成一個獨一無二的標識符。 - ②綁定(Bind)
C函數(shù):glBindBuffer()
—— 告訴OpenGl ES為接下來的運算使用一個緩存。 - ③緩存數(shù)據(jù)(Buffer Data)
C函數(shù):glBufferSubData()
—— 讓OpenGL ES為當前綁定的緩存分配并初始化足夠的連續(xù)內存(通過從CPU控制的內存復制數(shù)據(jù)到分配的內存)。 - ④啟用(Enable)或者禁止(Disable)
C函數(shù):glEnableVertexAttribArray()或者glDisableVertexAttribArray()
—— 告訴OpenGL ES在接下來的渲染中是否使用緩存中的數(shù)據(jù)。 - ⑤設置指針(Set Pointer)
C函數(shù):glVertexAttribPointer()
—— 告訴OpenGL ES在緩存中的數(shù)據(jù)的類型和所有需要訪問的內存偏移值。 - ⑥繪圖(Draw)
C函數(shù):glDrawArrays()或者glDrawElements()
—— 告訴OpenGL ES使用當前綁定并啟用的緩存中的數(shù)據(jù)渲染整個場景或者某個場景的一部分。 - ⑦刪除(Delete)
C函數(shù):glDeleteBuffer()
—— 告訴OpenGL ES刪除以前生成的緩存并釋放相關的資源。
幀緩存
概念:GPU需要知道應該在內存中的哪個位置存儲渲染出來的2D圖像像素數(shù)據(jù)。就像GPU提供數(shù)據(jù)的緩存一樣,接收渲染結果的緩沖區(qū)叫做幀緩存(frame buffer)。
- 幀緩存不需要初始化,因為渲染指令會在適當?shù)臅r候替換緩存的內容。幀緩存會在被綁定的時候隱式開啟,同時自動根據(jù)特定平臺的硬件配置和功能來設置數(shù)據(jù)的類型和偏移。
- 幀緩存可以同時存在很多個,并且可以通過OpenGL ES讓GPU把渲染結果存儲到任意數(shù)量的幀緩存中。
- 屏幕顯示像素受到保存在前幀緩存(front frame buffer)的特定幀緩存中的像素顏色元素控制。
- 程序和操作系統(tǒng)很少會直接渲染到前幀緩存中,因為那樣會讓用戶看到正在渲染中還誒與渲染完成的圖像。相反,會把渲染結果保存到包括后幀緩存(back frame buffer)在內的其他幀緩存中。
- 當渲染后的后幀緩存包含一個完成的圖像時,前、后幀緩存幾乎會瞬間切換。后幀緩存變成新的前幀緩存。
OpenGL ES的上下文
- 用于配置OpenGL ES的保存在特定平臺的軟件數(shù)據(jù)結構中的信息會被封裝到一個OpenGL ES上下文(context)中。
OpenGL ES是一個狀態(tài)機器,這意味著在一個程序中設置了一個配置值后,這個值會一直保持,知道程序修改了這個值。
上下文中的信息可能會被保存在CPU所控制的內存中,也可能被保存在GPU所控制的內存中。OpenGL ES會按需在兩個內存區(qū)域間復制信息。
OpenGL ES為使程序不需要知道太多與特定系統(tǒng)相關的信息,OpenGL ES為跟上下文交互提供了ANSI C語言函數(shù)。
OpenGL ES上下文會跟蹤用于渲染的幀緩存、用于幾何數(shù)據(jù)、顏色等的緩存。還會決定是否使用如紋理、燈光等功能以及會為渲染定義當前的坐標系統(tǒng)等。
一個3D場景的幾何數(shù)據(jù)
幾何數(shù)據(jù)是相對于3D坐標系定義的。
坐標系
-
OpenGL ES總是開始于一個矩形的笛卡爾坐標系,這意味著任何兩個軸之間的角度都是90°。空間中的每一個位置被稱為一個頂點,每個頂點通過其在X、Y、Z軸上的位置被定義。
X、Y、Z定義了OpenGL的坐標系 OpenGL ES坐標是以浮點數(shù)來存儲的。現(xiàn)代GPU對浮點數(shù)運算做了專門的優(yōu)化,即使使用其他數(shù)據(jù)類型的頂點也會被轉換成浮點值。
矢量
- 從某種意義上講,矢量是另一種詮釋頂點數(shù)據(jù)的方式。矢量是既有方向又有距離的一個量。所有的頂點可以用它相對于OpenGL ES坐標系原點({0, 0, 0})的距離和方向來定義。從原點到頂點的實心箭頭描述了矢量。虛線顯示頂點如何與坐標軸對齊。
在3D坐標中的一個矢量 - 矢量是理解現(xiàn)代GPU的關鍵,因為圖形處理器就是大規(guī)模并行矢量處理器。GPU能夠同時控制多個矢量,并執(zhí)行用于定義渲染結果的矢量運算。
- OpenGL ES的默認坐標系、頂點和矢量為要渲染的幾何數(shù)據(jù)的定義提供了足夠的數(shù)學元素。
點、線、三角形
- 一個頂點會定義坐標系中的一個點的位置,兩個頂點定義一個線段,三個頂點會定義一個三角形。
- OpenGL ES只渲染頂點、線段和三角形。
小結
- GPU控制的緩存是高效渲染的關鍵。
- 容納幾何數(shù)據(jù)的緩存定義了要渲染的點、線段和三角形。
- OpenGL ES的3D默認坐標系、頂點和矢量為幾何數(shù)據(jù)的描述提供了數(shù)學基礎。
- 渲染的結果通常保存在幀緩存中。其中有兩個特別的幀緩存:前幀緩存和后幀緩存,他們控制著屏幕像素的最終顏色。
- OpenGL ES的上下文保存了OpenGL ES的狀態(tài)信息,包括用于提供渲染的數(shù)據(jù)的緩存地址和用于接受緩存結果的緩存地址。