一、目的
掌握OpenGL中紋理對象的創建、綁定與使用方法。
二、簡單介紹
1,連接靜態庫
#pragma comment(lib, "glut32.lib") #pragma comment(lib, "glaux.lib")
2,載入位圖圖像到內存(這是固定用法)
AUX_RGBImageRec *LoadBMP(CHAR *Filename) { FILE *File = NULL; // 文件句柄 if (!Filename) // 確保文件名已提供 { return NULL; // 如果沒提供,返回 NULL } File = fopen(Filename, "r"); // 嘗試打開文件 if (File) // 判斷文件存在與否 { fclose(File); // 關閉句柄 return auxDIBImageLoadA(Filename); // 載入位圖並返回指針 } return NULL; // 如果載入失敗,返回 NULL }
3,載入位圖並轉換成紋理(固定用法)
int LoadGLTextures(GLuint *texture, char *bmp_file_name, int texture_id) { int Status = FALSE; // 狀態指示器 // 創建紋理的存儲空間 AUX_RGBImageRec *TextureImage[1]; memset(TextureImage, 0, sizeof(void *) * 1); // 將指針設為 NULL // 載入位圖,檢查有無錯誤,如果位圖沒找到則退出 if (TextureImage[0] = LoadBMP(bmp_file_name)) { Status = TRUE; // 將 Status 設為 TRUE //生成(generate)紋理 glGenTextures(texture_id, texture); //&texture[0]); //綁定2D紋理對象 glBindTexture(GL_TEXTURE_2D, *texture); //texture[0]); //關聯圖像數據與紋理對象 glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); //圖形繪制時所使用的濾波器參數 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 線形濾波 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 線形濾波 } //釋放圖像的內存,因為已經生成紋理了,沒用了 if (TextureImage[0]) // 紋理是否存在 { if (TextureImage[0]->data) // 紋理圖像是否存在 { free(TextureImage[0]->data); // 釋放紋理圖像占用的內存 } free(TextureImage[0]); // 釋放圖像結構 } else printf("紋理不存在"); return Status; // 返回 Status }
4,開始繪制
void DrawCube(void) // 從這里開始進行所有的繪制 { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度緩存 glLoadIdentity(); // 重置當前的模型觀察矩陣 glBindTexture(GL_TEXTURE_2D, texture[0]); // 選擇紋理 glBegin(GL_QUADS); // 前面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // 紋理和四邊形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f); // 紋理和四邊形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f); // 紋理和四邊形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 紋理和四邊形的左上 // 后面 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // 紋理和四邊形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // 紋理和四邊形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f); // 紋理和四邊形的左上 glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f); // 紋理和四邊形的左下 glFlush(); //glutSwapBuffers(); }
根據坐標關系,依次類推出頂面、底面、左面、右面的繪制方式。
三、示例代碼
#include "stdafx.h" #include <GL/glut.h> //引用相關包 #include <windows.h> #include <GL/glaux.h> #include <stdio.h> #include <stdlib.h> //注意下面的編譯指令——告訴編譯器要連接的靜態庫 #pragma comment(lib, "glut32.lib") #pragma comment(lib, "glaux.lib") GLfloat xrot = 0; // X 旋轉量 GLfloat yrot = 0; // Y 旋轉量 GLfloat zrot = 0; // Z 旋轉量 GLuint texture[1]; // 存儲一個紋理---數組 //載入位圖圖象到內存——固定用法 AUX_RGBImageRec *LoadBMP(CHAR *Filename) { FILE *File = NULL; // 文件句柄 if (!Filename) // 確保文件名已提供 { return NULL; // 如果沒提供,返回 NULL } File = fopen(Filename, "r"); // 嘗試打開文件 if (File) // 判斷文件存在與否 { fclose(File); // 關閉句柄 return auxDIBImageLoadA(Filename); // 載入位圖並返回指針 } return NULL; // 如果載入失敗,返回 NULL } //載入位圖(調用上面的代碼)並轉換成紋理——固定用法 //參數:紋理指針、bmp文件名、用戶指定的紋理編號 int LoadGLTextures(GLuint *texture, char *bmp_file_name, int texture_id) { int Status = FALSE; // 狀態指示器 // 創建紋理的存儲空間 AUX_RGBImageRec *TextureImage[1]; memset(TextureImage, 0, sizeof(void *) * 1); // 將指針設為 NULL // 載入位圖,檢查有無錯誤,如果位圖沒找到則退出 if (TextureImage[0] = LoadBMP(bmp_file_name)) { Status = TRUE; // 將 Status 設為 TRUE //生成(generate)紋理 glGenTextures(texture_id, texture); //&texture[0]); //綁定2D紋理對象 glBindTexture(GL_TEXTURE_2D, *texture); //texture[0]); //關聯圖像數據與紋理對象 glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data); //圖形繪制時所使用的濾波器參數 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // 線形濾波 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 線形濾波 } //釋放圖像的內存,因為已經生成紋理了,沒用了 if (TextureImage[0]) // 紋理是否存在 { if (TextureImage[0]->data) // 紋理圖像是否存在 { free(TextureImage[0]->data); // 釋放紋理圖像占用的內存 } free(TextureImage[0]); // 釋放圖像結構 } else printf("紋理不存在"); return Status; // 返回 Status } void DrawCube(void) // 從這里開始進行所有的繪制 { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度緩存 glLoadIdentity(); // 重置當前的模型觀察矩陣 glTranslatef(0.0f, 0.0f, -5.0f); // 移入屏幕 5 個單位 glRotatef(xrot, 1.0f, 0.0f, 0.0f); // 繞X軸旋轉 glRotatef(yrot, 0.0f, 1.0f, 0.0f); // 繞Y軸旋轉 glRotatef(zrot, 0.0f, 0.0f, 1.0f); // 繞Z軸旋轉 glBindTexture(GL_TEXTURE_2D, texture[0]); // 選擇紋理 glBegin(GL_QUADS); // 前面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // 紋理和四邊形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f); // 紋理和四邊形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f); // 紋理和四邊形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 紋理和四邊形的左上 // 后面 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // 紋理和四邊形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // 紋理和四邊形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f); // 紋理和四邊形的左上 glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f); // 紋理和四邊形的左下 // 頂面 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // 紋理和四邊形的左上 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 紋理和四邊形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, 1.0f, 1.0f); // 紋理和四邊形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f); // 紋理和四邊形的右上 // 底面 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // 紋理和四邊形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, -1.0f, -1.0f); // 紋理和四邊形的左上 glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f); // 紋理和四邊形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // 紋理和四邊形的右下 // 右面 glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f, -1.0f, -1.0f); // 紋理和四邊形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(1.0f, 1.0f, -1.0f); // 紋理和四邊形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f(1.0f, 1.0f, 1.0f); // 紋理和四邊形的左上 glTexCoord2f(0.0f, 0.0f); glVertex3f(1.0f, -1.0f, 1.0f); // 紋理和四邊形的左下 // 左面 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // 紋理和四邊形的左下 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // 紋理和四邊形的右下 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // 紋理和四邊形的右上 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // 紋理和四邊形的左上 glEnd(); glFlush(); //glutSwapBuffers(); xrot += 0.3f; // X 軸旋轉 yrot += 0.2f; // Y 軸旋轉 zrot += 0.4f; // Z 軸旋轉 } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清楚顏色數據和深度數據(清屏) glLoadIdentity(); // 重置視圖 glTranslatef(0.0f, 0.0f, -5.0f); DrawCube(); glutSwapBuffers(); //交換緩沖區。顯示圖形 } //初始化 void init(void) { glClearColor(1.0, 1.0, 1.0, 0.0); //清理顏色,為黑色,(也可認為是背景顏色) glCullFace(GL_BACK); //背面裁剪(背面不可見) glEnable(GL_CULL_FACE); //啟用裁剪 glEnable(GL_TEXTURE_2D); LoadGLTextures(&texture[0], "mf.bmp", 1); //載入紋理貼圖 //LoadGLTextures(&texture[1], "mf1.bmp", 2); //載入紋理貼圖 } //當窗口大小改變時,會調用這個函數 void reshape(GLsizei w, GLsizei h) { //這里小說明一下:矩陣模式是不同的,他們各自有一個矩陣。投影相關 //只能用投影矩陣。(只是目前情況下哦,等我學多了可能就知道為什么了。) glViewport(0, 0, w, h); //設置視口 glMatrixMode(GL_PROJECTION); //設置矩陣模式為投影變換矩陣, glLoadIdentity(); //變為單位矩陣 gluPerspective(60, (GLfloat)w / h, 0, 1000); //設置投影矩陣 glMatrixMode(GL_MODELVIEW); //設置矩陣模式為視圖矩陣(模型) glLoadIdentity(); //變為單位矩陣 } //鍵盤輸入事件函數 void keyboard(unsigned char key, int x, int y) { switch (key) { case 'x': //當按下鍵盤上d時,以沿X軸旋轉為主 xrot += 1.0f; //設置旋轉增量 glutPostRedisplay(); //重繪函數 break; case 'y': yrot += 1.0f; glutPostRedisplay(); break; case 'z': zrot += 1.0f; glutPostRedisplay(); break; default: break; } } int main(int argc, char *argv[]) { glutInit(&argc, argv); //固定格式 glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); //注意這里 glutInitWindowSize(600, 600); //顯示框的大小 glutInitWindowPosition(100, 100); //確定顯示框左上角的位置 glutCreateWindow("OpenGL紋理貼圖"); init(); //初始化資源,這里一定要在創建窗口以后,不然會無效。 LoadGLTextures(&texture[0], "mf.bmp", 1); glutDisplayFunc(display); glutReshapeFunc(reshape); //繪制圖形時的回調 glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }
四、注意
1.貼圖文件大小必須為:寬、高都必須為2的整數次冪,格式必須為BMP。
2.貼圖需要放在相應文件夾下,在編譯器中直接運行此程序可能會看不到貼圖效果。
點開箭頭所指的文件夾
放置需要貼紋理的位圖文件
五、總結
這是我在學校做的圖形學紋理貼圖實驗,放暑假了一直忙着准備考研,今天突然想起應該把以前做的實驗整理一下,於是找到了這個實驗。
紋理貼圖是一個很有趣的實驗,它就像一層嫁衣,為你所創建的目標對象披上一件外衣,讓別人看着賞心悅目,當然我目前所學的只是對規則物體進行紋理貼圖,以后還會遇到不規則的物體等。