用OpenGL進行立方體表面紋理貼圖


一、目的

掌握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();
}    

 

根據坐標關系,依次類推出頂面、底面、左面、右面的繪制方式。

 

三、示例代碼

Github地址

#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.貼圖需要放在相應文件夾下,在編譯器中直接運行此程序可能會看不到貼圖效果。

 點開箭頭所指的文件夾

 

放置需要貼紋理的位圖文件

 

五、總結

這是我在學校做的圖形學紋理貼圖實驗,放暑假了一直忙着准備考研,今天突然想起應該把以前做的實驗整理一下,於是找到了這個實驗。

紋理貼圖是一個很有趣的實驗,它就像一層嫁衣,為你所創建的目標對象披上一件外衣,讓別人看着賞心悅目,當然我目前所學的只是對規則物體進行紋理貼圖,以后還會遇到不規則的物體等。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM