1. 程式人生 > >Opengl es2.0 學習筆記(七)基礎紋理

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)
只要轉動紋理座標系,在與螢幕座標系重合,就可以對應處頂點座標,對應的紋理座標。