OpenGL繪製紋理的步驟:函數
使用glEnable(GL_TEXTURE_2D)開啓2D紋理功能,使用glDisable(GL_TEXTURE_2D)關閉紋理,默認狀況下紋理是關閉的。oop
讀取的時候注意如下3點:測試
使用函數glGenTextures(N,&textureID)來分配N個紋理編號,使用glTexParameteri來設置經常使用的4個紋理參數,這些參數包括了當前紋理圖像大小/小於模型目標時擴展紋理的處理方式。使用gltextImage2D函數根據指定的紋理參數生成一個2D紋理,函數原型是:ui
glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
在分配紋理以前最好先獲取一下程序當前所使用的紋理編號,而且在生成本次紋理以後恢復以前保存的紋理編號,從而保證不對當前程序產生影響。spa
經過gluPerspective和gluLookAt設置「視角」和「觀察點」的相關參數。操作系統
紋理映射跟顏色的繪製同樣,須要指定每個頂點在紋理圖像中所對應的位置,OpenGL會自動計算出頂點之間的其餘點在紋理圖像中應該對應的位置。這裏注意紋理圖像的座標範圍是從(0,0)到(1,1),左下角爲(0,0),右上角爲(1,1),鑑於以前已經在第3步中設置了座標點大於1或者座標點小雨0的狀況的處理方法,因此不考慮顯示效果的話,座標能夠任意指定。code
下邊代碼是紋理映射的應用:orm
#define WindowWidth 400 #define WindowHeight 400 #define WindowTitle "OpenGL紋理測試" #include <glut.h> #include <stdio.h> #include <stdlib.h> //定義兩個紋理對象編號 GLuint texGround; GLuint texWall; #define BMP_Header_Length 54 //圖像數據在內存塊中的偏移量 static GLfloat angle = 0.0f; //旋轉角度 // 函數power_of_two用於判斷一個整數是否是2的整數次冪 int power_of_two(int n) { if( n <= 0 ) return 0; return (n & (n-1)) == 0; } /* 函數load_texture * 讀取一個BMP文件做爲紋理 * 若是失敗,返回0,若是成功,返回紋理編號 */ GLuint load_texture(const char* file_name) { GLint width, height, total_bytes; GLubyte* pixels = 0; GLuint last_texture_ID=0, texture_ID = 0; // 打開文件,若是失敗,返回 FILE* pFile = fopen(file_name, "rb"); if( pFile == 0 ) return 0; // 讀取文件中圖象的寬度和高度 fseek(pFile, 0x0012, SEEK_SET); fread(&width, 4, 1, pFile); fread(&height, 4, 1, pFile); fseek(pFile, BMP_Header_Length, SEEK_SET); // 計算每行像素所佔字節數,並根據此數據計算總像素字節數 { GLint line_bytes = width * 3; while( line_bytes % 4 != 0 ) ++line_bytes; total_bytes = line_bytes * height; } // 根據總像素字節數分配內存 pixels = (GLubyte*)malloc(total_bytes); if( pixels == 0 ) { fclose(pFile); return 0; } // 讀取像素數據 if( fread(pixels, total_bytes, 1, pFile) <= 0 ) { free(pixels); fclose(pFile); return 0; } // 對就舊版本的兼容,若是圖象的寬度和高度不是的整數次方,則須要進行縮放 // 若圖像寬高超過了OpenGL規定的最大值,也縮放 { GLint max; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max); if( !power_of_two(width) || !power_of_two(height) || width > max || height > max ) { const GLint new_width = 256; const GLint new_height = 256; // 規定縮放後新的大小爲邊長的正方形 GLint new_line_bytes, new_total_bytes; GLubyte* new_pixels = 0; // 計算每行須要的字節數和總字節數 new_line_bytes = new_width * 3; while( new_line_bytes % 4 != 0 ) ++new_line_bytes; new_total_bytes = new_line_bytes * new_height; // 分配內存 new_pixels = (GLubyte*)malloc(new_total_bytes); if( new_pixels == 0 ) { free(pixels); fclose(pFile); return 0; } // 進行像素縮放 gluScaleImage(GL_RGB, width, height, GL_UNSIGNED_BYTE, pixels, new_width, new_height, GL_UNSIGNED_BYTE, new_pixels); // 釋放原來的像素數據,把pixels指向新的像素數據,並從新設置width和height free(pixels); pixels = new_pixels; width = new_width; height = new_height; } } // 分配一個新的紋理編號 glGenTextures(1, &texture_ID); if( texture_ID == 0 ) { free(pixels); fclose(pFile); return 0; } // 綁定新的紋理,載入紋理並設置紋理參數 // 在綁定前,先得到原來綁定的紋理編號,以便在最後進行恢復 GLint lastTextureID=last_texture_ID; glGetIntegerv(GL_TEXTURE_BINDING_2D, &lastTextureID); glBindTexture(GL_TEXTURE_2D, texture_ID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, pixels); glBindTexture(GL_TEXTURE_2D, lastTextureID); //恢復以前的紋理綁定 free(pixels); return texture_ID; } void display(void) { // 清除屏幕 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 設置視角 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(75, 1, 1, 21); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(-4, 7,7, 0, 0, 0, 0, 0, 1); glRotatef(angle, 0.0f, 0.0f, 1.0f); //旋轉 // 繪製底面以及紋理 glBindTexture(GL_TEXTURE_2D, texGround); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-8.0f, -8.0f, 0.0f); glTexCoord2f(0.0f, 3.0f); glVertex3f(-8.0f, 8.0f, 0.0f); glTexCoord2f(3.0f, 3.0f); glVertex3f(8.0f, 8.0f, 0.0f); glTexCoord2f(3.0f, 0.0f); glVertex3f(8.0f, -8.0f, 0.0f); glEnd(); // 繪製立面 glBindTexture(GL_TEXTURE_2D, texWall); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0.0f); glVertex3f(-6.0f, -3.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-6.0f, -3.0f, 5.0f); glTexCoord2f(2.0f, 1.0f); glVertex3f(6.0f, -3.0f, 5.0f); glTexCoord2f(2.0f, 0.0f); glVertex3f(6.0f, -3.0f, 0.0f); glEnd(); //繪製另一個立面 glBegin(GL_QUADS); glTexCoord2f(2.0f, 0.0f); glVertex3f(6.0f, -3.0f, 0.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(6.0f, 9.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(6.0f, 9.0f, 5.0f); glTexCoord2f(2.0f, 1.0f); glVertex3f(6.0f, -3.0f, 5.0f); glEnd(); glutSwapBuffers(); } void myIdle(void) { angle += 1.8f; if( angle >= 360.0f ) angle = 0.0f; display(); } int main(int argc, char* argv[]) { // GLUT初始化 glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(100, 100); glutInitWindowSize(WindowWidth, WindowHeight); glutCreateWindow(WindowTitle); glEnable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_2D); // 啓用紋理 texGround = load_texture("ground2.bmp"); //加載紋理 texWall = load_texture("wall2.bmp"); glutDisplayFunc(&display); //註冊函數 glutIdleFunc(&myIdle); glutMainLoop(); //循環調用 return 0; }
動圖效果:對象
gluDisplayFunc: 該函數用於註冊一個繪圖函數,只是註冊而不是調用,這時候不會當即執行註冊函數,操做系統會在必要時刻對窗體進行從新繪製操做,這時候就會調用執行註冊函數。blog
glutMainLoop:調用該函數以後,程序進入GLTU事件處理循環,讓全部跟「事件」有關的、任何已經註冊的函數無限循環執行,該函數不會返回。
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max):獲取當前版本OpenGL支持的最大紋理尺寸。
判斷一個整數是否是2的整數次冪的方法:使用n&(n-1)判斷,若是n是2的整次冪,則n的二進制形式表示裏應該只有一個1,其餘位所有爲0。例如對於8bit二進制00100000來講,n-1=00011111,則n&(n-1)結果應該是0,若是不爲0,則n不是2的整次冪。
gluScaleImage:這個函數調用適當的像素存儲模式改變一個像素圖像的大小來讀取源圖像的像素數據,而後把像素數據寫入新的目標圖像。簡單來講就是調整圖像大小。
glGenTextures:用於分配一個紋理對象的編號,能夠批量分配一系列紋理對象。
glGenIntegerv(GL_TEXTURE_BINGDING_2D,@last_texs):用於獲取當前綁定的紋理編號,把紋理編號放置如last——texs內。
glBindTexture:用於指定接下來操做的紋理對象的編號,操做包括指定紋理像素、指定紋理參數、指定紋理座標等。這些操做都會應用在glBindTexture裏綁定的紋理對象上。若是不指定,默認會在編號爲0的紋理對象上操做。
glTexParameteri:用來設置紋理參數,一般須要設置的參數有4個:
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE):設置紋理跟材質的融合方式,不一樣的設置能夠產生不一樣的效果,默認爲GL_REPLACE,即只是用紋理,覆蓋模型的材質。
glTexImage2D:用於載入一個二維的紋理。
glTexCoord2f:用於繪製圖形時指定紋理的座標。