天天看點

OpenGL程式設計指南2D部分【下】4. 顔色、像素和幀緩存5. 視圖變換,剪切和回報6. 紋理附1. 遇到的坑

自己用Laravel寫的小部落格和CSDN的部落格以後同步更新:

OpenGL程式設計指南2D部分【下】

4. 顔色、像素和幀緩存

顔色

OpenGL需要RGB/sRGB格式的顔色

Fragment shader中指定顔色為頂點顔色,會使用高洛德着色填充區域

光栅

處于vertex shader和fragment shader之間

處理每個像素的buffer

多重采樣

一種簡潔的實作抗鋸齒的方法

需要程式提供一個額外的多重采樣緩存,使用時無法同時使用點線面平滑處理

可以通過glGetIntererv(GL_SAMPLE_BUFFERS)檢測緩存是否存在

需要提供采樣次數,最大次數通過

fragment shader中的sample關鍵字不知道怎麼用,加上即黑屏。

glMinSampleShading使用起來并沒有什麼效果

緩存

OpenGL有顔色緩存,深度緩存和模闆緩存,共同構成幀緩存

通過glClear[type]設定緩存清除預設值

通過gl[type]Mask來決定那些緩存可以寫入

測試

一個像素點需要經過:

1. 裁剪測試

2. 多重采樣操作

3. 模闆測試

4. 深度測試

5. 混合

6. 抖動

7. 邏輯操作

裁剪是控制一個矩形,隻能繪制在這個矩形當中。

使用glScissor設定矩形,glEnable開啟測試

預設多重采樣不考慮alpha,通過glEnable開啟特殊模式可以考慮alpha

模闆測試通過glStencilFunc設定測試的标準值和測試操作

通過glStencilOp設定測試完成的操作

可以先将測試設為一定通過,然後設定測試完成之後修改值,繪制一個模闆

然後将測試設為正常值,繪制圖像

深度測試預設可以控制頂點繪制時後面的點不會覆寫前面的點

可以通過glDepthFunc控制測試操作類型

混合是兩個不透明顔色如何繪制在一個點上

表達式:Cr = S * Cs + D * Cd

通過glBlendFunc控制混合方式

通過glBlendColor設定混合顔色常量

通過glBlendEquation控制計算符号

抖動是一種半色調的提高表現品質的方法

邏輯操作可以将顔色與目前幀緩存裡面的顔色進行操作

産生新的顔色,通過glLogicOp來控制操作方法

多邊形偏移

如果給多邊形畫邊框,因為深度相同,但是光栅對于多邊形和線條操作不同

會導緻邊框若隐若現,通過glEnable打開偏移功能,glPolygonOffset設定

可以将多邊形或者線條的深度偏移一下,保證繪制正常

遮擋查詢

通過渲染一個架構,确認這個架構是否可見來決定是否渲染架構中的多邊形

達到節省渲染資源的目的,過程如下:

  1. 建立查詢ID
  2. 開始查詢
  3. 繪制多邊形
  4. 結束查詢
  5. 檢視結果

通過glGenQueries建立ID,調用glBeginQuery開始查詢,調用glEndQuery結束查詢

在通過glGetQueryObjectiv來查找查詢結果

條件渲染

通過遮擋查詢的結果可以通過glBeginConditionalRender來繼續繪制

如果查詢不成功則繪制指令無效

通過glEndConditionalRender結束條件繪制

可以提高效率

逐圖元抗鋸齒

通過glHint設定抗鋸齒的模式,開啟blend設定blendfunc即可。

幀緩存

顯示在螢幕上幀緩存隻有一個,不過可以自己建立幀緩存以達到離屏渲染。

可以通過glGenFramebuffer來建立幀緩存。相對的有glBindFramebuffer和glDeleteFrameBuffer。

通過glGenRenderbuffer來建立渲染緩存。相對的有glBindRenderbuffer和glDeleteRenderBuffer。

有了渲染緩存之後要對它建立存儲空間,通過glRenderbufferStorage[Multisample]

可以将渲染緩存綁定到幀緩存中作為任意緩存。

幀緩存可以設定為繪制或者讀取模式,友善幀緩存之間拷貝資料。

glClearBuffer可以指定清除哪一個緩存。

glInvalidateFramebuffer可以删除幀緩存。

同時寫入多個渲染緩存

通過設定将不同的fragment shader輸出導入到不同渲染緩存實作

通過glBindFragDataLocation通知編譯器将輸出名稱綁定到位置

編譯完成後通過glGetFragDataLocation擷取位置

設定繪制緩存

通過glDrawBuffer設定一個應該被寫入的緩存

通過glReadBuffer設定一個應該被獨處的緩存

雙源混合

通過index=2的輸出函數決定混合時所用的系數。

讀取寫入像素點

通過glReadPixels讀取緩存中像素點

通過glClampColor将資料normalized

通過glBlitFrameBuffer在不同的緩存之間拷貝像素

5. 視圖變換,剪切和回報

基本的視圖變換都是通過變換矩陣和向量相乘得到

為了友善平移操作,我們向量變為四位齊次向量

轉換矩陣

平移矩陣:vmath::translate

縮放矩陣:vmath::scale

旋轉矩陣:vmath::rotate (歐拉旋轉)

透視投影:

vmath::frustum調整錄影機zoom和遠近兩個面

vmath::lookAt調整錄影機方向

正交投影:vmath::ortho

轉換法向量

轉換矩陣的逆的轉置乘以法向量可得法向量的轉換

OpenGL轉換

glDepthRange告訴OpenGL深度的繪制範圍

glViewport告訴OpenGL視口的大小

z軸精度

精度會随着z軸變大逐漸減小

使用者剪切

提供的一種讓使用者自主切割圖元和frustum相交的地方

變換回報

可通過把vertex shader計算之後的結果存入buffer來實作回報

通過把回報的資料繼續送入vertex shader可以實作gpu自動控制的粒子效果

6. 紋理

紋理類型

紋理有多種不同的類型,不同類型的紋理應該使用不同的sampler

建立紋理

  1. 通過glGenTexture建立紋理對象
  2. 通過glBindTexture綁定對象至一個綁定點
  3. 通過glActiveTexture将目前綁定的對象激活至某個紋理
  4. 通過glTexStorage[]将給對象配置設定紋理空間
  5. 通過glTex[]Image[]給對象紋理資料
  6. 通過glUniform1i配置設定紋理序号給sampler
  7. 在shader中使用texture擷取texel

内部類型

opengl内部使用來存儲紋理資料的方式,

可以是某種壓縮類型。

外部類型

提供給opengl紋理資料的類型,

可以是某種打包類型。

向opengl提供資料

直接提供:通過glTexSubImage。

間接提供:通過glTexSubImage将指針設定為0,并且綁定一個PIXEL_UNPACK_BUFFER。

從幀緩存讀取

通過glCopyTexImage1D從幀緩存讀取已經渲染完成的緩存内容

紋理對象

通過glGetTexImage從紋理對象中讀取紋理資料

通過glPixelStorei決定opengl存儲紋理資料的方式

取樣器

一種用來友善從紋理中讀取texel的工具

預設取樣器效果比較好

壓縮的紋理

通過使用glCompressedTexImage來使用壓縮的紋理

過濾

經常的情況下,texture的點和螢幕的點并不是精準對應

是以需要filter來取樣

線性取樣比較平滑,最近取樣比較銳利

mipmap

mipmap用來将texture分為多個精度,

在不同的距離,使用不同精度的map。

提高效率,優化表現。

使用glGenerateMipmap生成mipmap

進階texture函數

textureLod自定義mipmap層級

textureGrad自定義漸變

textureOffset提取texel時指定偏移

textureProj投影時對texel提取進行變換

textureQueryLod讀取texel的mipmap資訊

textureSize讀取texture大小資訊

textureGather讀取四個取樣點

以上函數還有各種組合版

點精靈

通過一個點完成對一個矩形的渲染,提高效率

通過glPointParameter來決定點精靈的樣子

向紋理圖渲染

删除幀緩存

附1. 遇到的坑

  • element_array_buffer的建立必須在VAO建立之後,不然會黑屏。
  • glVertexAttribPointer中的stride為0的時候表示資料緊密相鄰,但是并不是說stride是資料間隔,當stride不為0時代表的兩個點資料間隔的距離加上點資料的大小。

繼續閱讀