複習 OpenGL 紋理對映 總結

2021-08-15 16:30:11 字數 3670 閱讀 3075

今天系統的複習了一下opengl紋理對映

主要參考資料是這兩個 opengl 教程

總體來看,第二個教程更詳盡一些,比第乙個教程多介紹了一下 如何把 texture2d 物件,傳到 fragment shader 的 sampler2d 的 uniform 變數中。

很久以前,自己總結過opengl texture2d 使用的關鍵步驟

opengl 使用 texture2d 關鍵步驟

今天再結合現在的經驗補充幾點。

opengl texture2d 物件 的生成,其實和 乙個 vbo 的生成步驟類似。

首先是 generate 

vbo 是  glgenbuffers(1,&_vbo);

texture 是 glgentextures(1,&_tex);

然後,需要 bind ,才能指明要操作哪個 vbo / 哪個 texture2d

vbo : glbindbuffer(_vbo);

texture: glbindtexture(_tex);

接下來,就是真正把記憶體中的資料,儲存到緩衝區內.

vbo 使用 glbufferdata()

texture 使用 glteximage2d()

針對 vbo 來說,通常是頂點的位置資料,顏色資料,uv資料,法線資料等等模型頂點相關的資料。至於這些頂點的資料,是直接寫在**的 陣列裡面的,還是 從 模型檔案裡讀取的,這些opengl 都不關心,只要把資料的指標準備好,用 glbufferdata() 儲存到vbo就好了。

相應的,對於 texture2d 來說,glteximage2d() 是把一段表示每個畫素顏色資訊的 記憶體資料,儲存到  texture 裡。同樣它也並不關心資料的來路。無論是讀取,還是自己在記憶體裡手寫,無論是 bmp ,jpg,png ,tga 格式, 無論是否帶 alpha 通道,這些都無所謂,只要有資料指標就行。

但是區別的地方在於,glteximage2d 需要關心 顏色資訊的具體格式,也就是說 它有些引數,需要知道 這段記憶體資料交由它之後,它要如何理解。比如是 rgb 還是 rgba ,每個畫素 所佔位數 等資訊。

二者之間有所區別的原因是 ,vbo 裡的資料,能夠通過 vao 傳到 shader 裡,可以自己隨意編寫 glsl 來解析。但是 sampler2d 型別的資料,在 shader 裡面 的 靈活性 就要差很多,在 shader 裡面使用時,顏色資訊已經通過傳引數決定了,沒有更多底層的細節暴露出來。所以 給 texture 一段記憶體資料時,引數要更加明確,讓 gl 知道 每個畫素的顏色 在記憶體裡 是如何排布的。

vbo ,texture2d 二者相同:資料給到 opengl 之後,記憶體裡的資料就可以釋放了,因為資料已經儲存到了 opengl 的視訊記憶體裡 (?).所以資料指標 指向的記憶體,可以盡快 delete 銷毀 .

說到資料載入到記憶體,最簡單的資料格式,應該是 bmp 格式,因為它 基本上就是把每個畫素的顏色值,按照順序擺放在 檔案裡,所以解析起來非常方便。

這裡有一篇自己以前的總結

裡面有現成的自己手寫的解析 24位 bmp 格式的**。每個教程在取畫素資料時,都使用了不同的庫。我這次複習時,使用的解析「庫」 就是 上面鏈結裡 ,自己手寫的 解析 24 位 bmp 的 **。它可以將解析為乙個the24bitbmp物件,此物件包含 的 寬度,高度,包含顏色資料的乙個 連續 記憶體的指標。給 opengl 的 glteximage2d() 做引數 完全夠用。

texture2d 已經準備好了,在使用時,有幾個值得留意的地方。

1. texture2d 是一張,體現在 shader 裡,通常是 fragment shader 裡的乙個 sampler2d 的 uniform 變數。形如 uniform sampler2d mytexturesampler;

那麼,如何把 c++ **裡的 gluint texture2d 與 shader 裡的 sampler2d 變數 聯絡起來呢 ?

方法類似  vao .

vao 是 vbo 資料 到 vertex shader 引數 的乙個橋梁。vao 負責用 glenablevertexattribarray()  來控制 shader 開啟/關閉 vertex shader 裡面 哪些 in 型別的變數。

而 glactivetexture(gl_texture0 ... n ) 用於決定開啟 哪些 texture2d 物件,可以給 fragment shader 呼叫。

預設 gl_texture0 總是開啟的。

通過 glactivetexture(gl_texture ...n) 告訴 shader 第 n 個 texture2d 開啟了

然後通過 glbindtexture(gl_texture_2d,_tex) 告訴 第 n 個 texture2d 物件 究竟 對應哪個資料。

最後,把 shader 裡面 sampler2d 的變數名, 和 c++ 裡面 texture2d 物件真正對應起來, 是依靠 gluniform1i().

比如 fragment shader 裡 ,有個 uniform 的 sampler2d 變數 名叫 outtexture1 ,它想要對應 c++ 裡 gl_texure1 這張,則** 如下 :

gluniform1i(glgetuniformlocation(shaderprogram, "outtexture1"),1);

這樣,通過 

glactivetexture(gl_texturen)

glbindtexture(gl_texturen,tex)

gluniform1i(glgetuniformlocation(shaderprogram, "著色器裡的變數名"),n);

這 3個函式組合的套路, 就真正的把 一張的顏色資訊,傳遞到 shader 裡面了。

在 fragment shader 裡最終使用時,就可以簡單的通過

color = texture(texturesampler,uv).rgb

來輸出,顯示 的顏色了。

uv 引數的傳遞方法,和  頂點位置資料,頂點顏色資料 的傳遞方法完全一樣。

uv 就是 該點 所對應 在 裡的2d座標,所以是乙個 vec2 型別的變數。需要通過 vbo->vao->vertexshader->fragmentshader 這樣乙個完整的流程,最終傳遞到  fragment shader 裡面去。

總結一下,如果想渲染乙個 帶有的 多邊形,需要經過如下幾個關鍵步驟 :

1. 多邊形位置資料陣列

2.位置資料陣列 -> posvbo

3. 多邊形各個頂點 uv 資料陣列

4.uv資料陣列 -> uvvbo

5.解析各畫素顏色資料,存到乙個 陣列中

6.顏色資料陣列 -> 儲存到 texture2d 的 handle 中

7. 編寫 vertex shader ,包含 vertex pos ,vertex uv

8. 編寫 fragment shader ,包含  uv ,和 sampler2d 

9. 生成 vao ,把 posvbo ,uvvbo 傳遞到 vertex shader 

10. 啟用 和 使用 gl_texture0(n) ,把 texture2d 的 handle 與 fragment shader 的 sampler2d 變數對應起來

11. 做最終渲染

經過這麼一大串 折騰,才能在 opengl 裡看到乙個能夠顯示 的麵片。

下一步繼續跟著教程走,做好 鍵盤滑鼠控制 鏡頭移動,再下一步是 讀取 model 檔案的資料,和 手寫 頂點資料說拜拜。

OpenGL 紋理對映Mipmap

mipmap是乙個功能強大的紋理技術,它可以提高渲染的效能以及提公升場景的視覺質量,它可以用來解決一般紋理貼圖出現的兩個常見問題 閃爍,當螢幕上被渲染物體的表面與它所應用的紋理影象相比顯得非常小時,就會出現閃爍,尤其當相機和物體在移動的時候,這種負面效果更容易出現。效能問題,載入了大量紋理資料之後,...

OpenGL 7 紋理對映

紋理對映前,首先自定義讀取點陣圖的函式,其返回型別為aux rgbimagerec 該結構體定義在glaux.h中 aux rgbimagerec loadbmp char filename file fopen filename,r if file return null 載入失敗,返回null ...

opengl紋理單元

可以這樣簡單的理解為 顯示卡中有n個紋理單元 具體數目依賴你的顯示卡能力 每個紋理單元 gl texture0 gl texture1等 都有gl texture 1d gl texture 2d等,如下 cpp view plain copy print struct textureunit te...