Opengl es2.0 學習筆記(七)基礎紋理
一.使用紋理過程
-
使用FreeImage.lib 讀取圖片,獲取調色盤.(windows顏色不是rgb是bgr,此處需要轉換)
-
glGenTextures建立一個紋理控制代碼
-
glBindTexture關聯紋理
-
glTexParameteri設定紋理引數
-
glTexImage2D上傳到opengl
經過上述步驟我們的紋理控制代碼就可以使用了
繪製過程
//! 清空緩衝區 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); //! 視口,在Windows視窗指定的位置和大小上繪製OpenGL內容 glViewport(0,0,_width,_height); //繫結紋理 glBindTexture(GL_TEXTURE_2D,_textureId); //傳入正交投影矩陣 4*4 glUniformMatrix4fv(_shader._MVP, 1, false, matMVP.data()); //傳入紋理ID,並且設定為0級紋理 glUniform1i(_shader._texture, 0); //傳入頂點座標 glVertexAttribPointer(_shader._position,2, GL_FLOAT, false, sizeof(Vertex),vertex); //傳入uv座標,即紋理座標 glVertexAttribPointer(_shader._uv,2, GL_FLOAT, false, sizeof(Vertex),&vertex[0].uv); //傳入頂點顏色 glVertexAttribPointer(_shader._color, 4, GL_UNSIGNED_BYTE, true, sizeof(Vertex),&vertex[0].color); glDrawArrays(GL_TRIANGLE_STRIP,0,4);
//shader中程式碼 const char* vs = { "precision lowp float; " //指明精度 "uniform mat4 _MVP;" //正交投影 "attribute vec2 _position;" //傳入頂點位置 "attribute vec4 _color;" //顏色 "varying vec4 _outColor;" //傳遞給片段著色器 "void main()" "{" " vec4 pos = vec4(_position,0,1);"//獲取位置 " _outColor = _color;" //輸出顏色賦值 " gl_Position = _MVP * pos;" //輸出的位置 "}" }; const char* ps = { "precision lowp float; " "varying vec4 _outColor;" "void main()" "{" "vec4 tColor = texture2D(_texture,_outUV);\n"//取顏色 " gl_FragColor = tColor*_outColor;" //加法是沒有關係的顏色之間的疊加,而乘法是模擬光的照射過程 "}" };
二.疑惑:
// index: 著色器指令碼對應變數ID // size : 此型別資料的個數 // type : 此型別的sizeof值 // normalized : 是否對非float型別資料轉化到float時候進行歸一化處理 // stride : 此型別資料在陣列中的重複間隔寬度,byte型別計數 // ptr : 資料指標 glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);glDrawArrays(GL_TRIANGLE_STRIP,0,4);
問題來了,opengl上哪知道資料取多少呢?
答案:
我們使用這個函式,會指明我們要畫的點的數量,這樣opengl就知道我們需要取多少個元素了
glDrawArrays (GLenum mode, GLint first, GLsizei count);
三.API:
//產生一個紋理Id,可以認為是紋理控制代碼,後面的操作將書用這個紋理id
glGenTextures( 1, &textureId );
//使用這個紋理id,或者叫繫結(關聯)
glBindTexture( GL_TEXTURE_2D, textureId );
/**
*指定紋理的放大,縮小濾波,使用線性方式,即當圖片放大的時候插值方式
*/
//GL_TEXTURE_MAG_FILTER放大濾波
//GL_TEXTURE_MIN_FILTER縮小濾波
//GL_LINEAR 指定線性演算法,效率低一些,質量好一些
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
/**
- 將圖片的rgb資料上傳給opengl.
*/
glTexImage2D(
GL_TEXTURE_2D, //! 指定是二維圖片
0, //! 指定為第一級別,紋理可以做mipmap,即lod,離近的就採用級別大的,遠則使用較小的紋理
GL_RGB, //! 紋理的使用的儲存格式
width, //! 寬度,老一點的顯示卡,不支援不規則的紋理,即寬度和高度不是2^n。
height, //! 寬度,老一點的顯示卡,不支援不規則的紋理,即寬度和高度不是2^n。
0, //! 是否的邊
GL_RGB, //! 資料的格式,bmp中,windows,作業系統中儲存的資料是bgr格式
GL_UNSIGNED_BYTE, //! 資料是8bit資料,RGBA是8bit位
pixels
);
四.座標
螢幕座標:就是應用在裝置螢幕上的座標系。也就是圖形最終繪製的地方。
左上角為原點,箭頭為正方向,大小又螢幕畫素大小決定。openGL的螢幕座標系,Y軸向上為正。相當於上面那個三維座標系擷取一個二維的XY。
opengl座標:
分3個軸,x,y,z 中心點為o, 箭頭方向為正方向,最大與最小值為1和-1,這是經過歸一化處理的。這樣設計是為了顯示卡計算方便。
texture座標
:
也做了歸一化處理。這個座標就代表了一個紋理。openGL是基於定點的網格繪製。就是說,openGL的圖形都是由很多頂點,按照一定的規則連結起來構成的圖形。那麼紋理座標的4個座標點,對映到頂點上。openGL就會把這個紋理應用到4個定點構成的圖形上。
五.紋理貼圖的座標變化:
我們通常使用頂點座標是 :
螢幕座標和 mvp矩陣,傳入shader,然後 shader中輸出點的變數
gl_Position = 螢幕座標 X mvp矩陣 ,轉換為了opengl座標即-1~+1,螢幕中心點0,0為中心的座標系
六.座標對應表
紋理座標的座標系如下:
- 紋理座標的 0,1相等於螢幕座標的0,0
- 紋理座標的1,0 相等於螢幕座標的x,y
- 紋理座標的1,1 相等於螢幕座標的x,0
- 紋理座標的0,0 相等於螢幕座標的 0,y
如下表:
頂點座標 | 紋理座標 |
---|---|
CELL::float2(x,y) | CELL::float2(0 ,1) |
CELL::float2(x + w,y) | CELL::float2(1 ,1) |
CELL::float2(x,y + h) | CELL::float2(0 ,0) |
CELL::float2(x + w, y + h) | CELL::float2(1 ,0) |
如果紋理要順時針轉動:
螢幕座標 | 紋理座標 |
---|---|
CELL::float2(x,y) | CELL::float2(0 ,0) |
CELL::float2(x + w,y), | CELL::float2(0 ,1) |
CELL::float2(x,y + h) | CELL::float2(1 ,0) |
CELL::float2(x + w, y + h) | CELL::float2(1 ,1) |