前言
最近觀看下面這本書有感,結合之前的學習,對OpenGL的知識進行回顧。
概念
幀緩存:接收渲染結果的緩沖區,為GPU指定存儲渲染結果的區域。
幀緩存可以同時存在多個,但是屏幕顯示像素受到保存在前幀緩存(front frame buffer)的特定幀緩存中的像素顏色元素的控制。
程序的渲染結果通常保存在后幀緩存(back frame buffer)在內的其他幀緩存,當渲染后的后幀緩存完成后,前后幀緩存會互換。(這部分操作由操作系統來完成)
前幀緩存決定了屏幕上顯示的像素顏色,會在適當的時候與后幀緩存切換。
- (BOOL)presentRenderbuffer:(NSUInteger)target;
Core Animation的合成器會聯合OpenGL ES層和UIView層、StatusBar層等,在后幀緩存混合產生最終的顏色,并切換前后幀緩存;
OpenGL ES坐標是以浮點數來存儲,即使是其他數據類型的頂點數據也會被轉化成浮點型;
framebuffer object 通常也被稱之為 FBO,它相當于 buffer(color, depth, stencil)的管理者,三大buffer 可以附加到一個 FBO 上。我們是用 FBO 來在 off-screen buffer上進行渲染。
GPU運算和CPU運算是分開的。(如果需要同步返回,可以使用glFinish
)
glReadPixels
從圖形硬件中復制數據,通常通過總線傳輸到系統內存。此時,應用程序將被阻塞,直到內存傳輸完成。
如果指定的像素布局與圖像硬件的本地排列不同,數據進行重定格式會產生額外的性能開銷。
在使用完緩存后,可以調用glBindBuffer
把array綁定的對象重置為0,防止被其他地方誤用;(注意,紋理對象需要在使用完后,再glBindTexture綁定為0)
CAEAGLLayer會與OpenGL ES的幀緩存共享它的像素顏色倉庫。(這也是為什么我們想讓繪制的內容顯示到屏幕時,需要重載UIView的+layerClass方法,返回一個CAEAGLLayer實例。)
eaglLayer的屬性kEAGLDrawablePropertyRetainedBacking為NO表示,不要試圖保留任何以前繪制的圖像留作以后重用。
在自定義UIView實現渲染時,需要在調整視圖大小的回調中(layoutSubviews),調用-renderbufferStorage:fromDrawable: 方法來調整視圖的尺寸,從而匹配層的新尺寸。
這個尺寸大小可以用glGetRenderbufferParameteriv()
方法來獲取;
glGetError
返回錯誤,如果有多個錯誤,每次返回一個,需要多次調用。
CoreGraphics負責創建顯示到屏幕上的數據模型,QuartzCore(CoreAnimation –> OpenGLES)負責把CoreGraphics創建的數據模型真正顯示到屏幕上。
理想狀態下,緩存生成后就不發生變化;
生成、初始化和刪除緩存需要耗費時間來同步GPU和CPU,大多數情況下是CPU等待GPU,因為GPU在刪除緩存之前必須等待該緩存相關的指令全部執行完畢;
故而一個程序在每幀都進行生成和刪除緩存會有嚴重的性能消耗。
glDeleteFramebuffers
glDeleteRenderbuffers
glDeleteBuffers
坐標
齊次坐標表示法:用n+1維向量表示n維向量。
齊次坐標歸一化,最后一個坐標為1。
If set to GL_TRUE, normalized indicates that values stored in an integer format are to be mapped to the range [-1,1]
整數才能歸一化,浮點數無效。
萬向節死鎖:Wiki解釋
如果是用高度角和偏航角來解釋,就是當高度角等于90°的時候,偏航角的維度已經丟失,不管你怎么轉都不會產生結果。
Gimbal_lock不是說空間存在某個點無法用極坐標的方式來表示,而是點的運動不能用連續的極坐標來表示。
紋理
紋理坐標系:S和T組成的2D軸。(0.0到1.0,還有1D和3D的紋理坐標系,R,S,T軸)
位圖(bitmap):一系列表示開啟和關閉像素值的0和1。
像素數據 != 位圖。
像素圖(pixmap):類似位圖,每個像素需要一個以上的存儲位來表示。
The more general term pixmap refers to a map of pixels, where each one may store more than two colors, thus using more than one bit per pixel. Often bitmap is used for this as well. In some contexts, the term bitmap implies one bit per pixel, while pixmap is used for images with multiple bits per pixel.
圖像數據在內存中很少以緊密的形式存在,出于性能的考慮,每一行都該從特定的字節對齊地址開始。
OpenGL 采用4個字節的對齊方式。
存儲大小 != 像素寬度 * 高度值。
應該是每行寬度 * 高度值,每行寬度可能會有填充的空字節。
1、紋理過濾
GL_TEXTURE_MIN_FILTER 表示多個紋素對應單個像素的時候
GL_TEXTURE_MAG_FILTER表示單個紋素對應多個像素的時候
GL_LINEAR 表示線性插值
GL_NEAREST 表示最近
2、紋理環繞
GL_TEXTURE_WRAP_S 表示S軸超過坐標系范圍
GL_TEXTURE_WRAP_T 表示T軸超過坐標系范圍
GL_CLAMP_TO_EDGE 表示取紋理邊緣
GL_REPEAT 表示重復紋理
GL_MIRRORED_REPEAT 表示鏡像重復紋理
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
OpenGL ES推薦使用尺寸為2的冪的紋理,其他紋理也支持,但是性能上會有額外的消耗。
3、各向異性過濾
非OpenGL標準的擴展支持,GL_EXT_texture_filter_anisotropic。
4、MIP紋理
glGenerateMipmap生成。
MIP紋理會比普通大33%,計算公式如下:
1 + 1/4 + 1/16 + 1/64 ... + 1/(4^n)
根據等比求和公式得到Sn = 1+1/3
glPixelStorei 方法可以改變或者恢復像素的存儲方式
GL_PACK_ALIGNMENT
GL_UNPACK_ALIGNMENT
默認4字節對齊,即一行的圖像數據字節數必須是4的整數倍,即讀取數據時,讀取4個字節用來渲染一行,之后讀取4字節數據用來渲染第二行。對RGB 3字節像素而言,若一行10個像素,即30個字節,在4字節對齊模式下,OpenGL會讀取32個字節的數據,若不加注意,會導致glTextImage中致函數的讀取越界崩潰。
One value affects the packing of pixel data into memory: GL_PACK_ALIGNMENT
. The other affects the unpacking of pixel data from memory: GL_UNPACK_ALIGNMENT
https://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml
默認是4字節讀取。
當著色器計算出來一個完全不透明的像素顏色時,可以簡單的替換幀緩存中對應位置的顏色,也可以通過glEnable(GL_BLEND)來開啟混合功能,并通過glBlendFunc設置混合函數。
也可以通過gl_LastFragData,自己計算混合后的顏色;
也可以通過多重紋理來實現。
多通道渲染:多次讀寫像素顏色緩存來創建一個最終的渲染結果的過程;
(舉例:開啟混合,只有紋理單元0,先綁定為紋理1,繪制;再綁定紋理2,繪制;再綁定紋理3,繪制;這樣得到最后的結果,是3張圖片混合后的結果)
glTexImage2D (1D和3D在ES2的頭文件沒找到,3D可以在ES3找到)加載紋理,紋理對象需要通過glGenTexture和glDelete 來創建和銷毀。
glTexSubImage2D 是替換紋理,可以替換部分,也可以替換全部紋理,速度比重新加載更快。
glCopyTexImage2D 可以用顏色緩沖區加載數據。
glCopyTexSubImage2D 同上。
在銷毀紋理的時候,如果不確定對象索引是否是紋理(比如作為參數傳遞),glIsTexture來判斷。
紋理高級知識
1、矩形紋理
GL_TEXTURE_RECTANGLE
不能進行MIP貼圖,只能加載glTexImage2D的第0層。 紋理坐標不是標準化的,紋理坐標實際上是對像素尋址,而不是從0到1的范圍覆蓋圖像的。
紋理坐標(5,19)實際上是圖像中從左起6個像素以及從上面起第20個像素。
2、立方體紋理
由6個正方形的2D圖像組成的紋理。
3、多重紋理
同時使用兩個或者更多紋理。
4、點塊紋理
在一個頂點上應用紋理。
紋理數組、紋理代理略。
基本圖形光柵化
1、直線
暴力法:微分方程,帶入坐標,取整求解(x,y);
中點畫線法:假設斜率在0~1之間,對于P(x, y),下一個點只能在P1或者P2,求P1P2中點M,直線與P1P2交點Q,判斷M、Q的上下關系;
bresenham畫線法:假設斜率在0~1之間,對于P(x, y),下一個點只能在P1或者P2,直線與P1P2交點為Q,判斷P1Q和QP2的大小關系;
2、圓
圓具有八對稱性,對于一個愿只需要繪制1/8的圓弧;
圓的bresenham,用D(P)來表示點P到原點的距離平方和圓的半徑平方之差,
di = D(Si) + D(Ti)。
超級寶典遇到的問題
1、gltReadTGABits錯誤
因為沒有引入頭文件和對應的cpp文件。
2、Invalid storage qualifiers 'in' in global variable context
改成 attribute 和 varying
3、不支持的version
以下是對應的GLSL版本