OpenGL紋理案例

使用OpenGL常用的API,繪制一個簡單的隧道模型并貼圖。最終下過如下:

1.gif

完成代碼:

#include "GLTools.h"
#include "GLShaderManager.h"
#include "GLFrustum.h"
#include "GLBatch.h"
#include "GLFrame.h"
#include "GLMatrixStack.h"
#include "GLGeometryTransform.h"

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

GLShaderManager     shaderManager;          //著色器管理器
GLMatrixStack       modelViewMatrix;        //模型視圖矩陣
GLMatrixStack       projectionMatrix;       //投影矩陣
GLFrustum           viewFrustum;            //視景體
GLGeometryTransform transformPipeline;      //幾何變換管線

//4個批次容器類
GLBatch             floorBatch;//地面
GLBatch             ceilingBatch;//天花板
GLBatch             leftWallBatch;//左墻面
GLBatch             rightWallBatch;//右墻面

//深度初始值,-65。
GLfloat             viewZ = -60.0f;

// 紋理標(biāo)識符號
#define TEXTURE_BRICK   0 //墻面
#define TEXTURE_FLOOR   1 //地板
#define TEXTURE_CEILING 2 //紋理天花板
#define TEXTURE_COUNT   3 //紋理個數(shù)

GLuint  textures[TEXTURE_COUNT];//紋理標(biāo)記數(shù)組
//文件tag名字?jǐn)?shù)組
const char *szTextureFiles[TEXTURE_COUNT] = { "brick.tga", "floor.tga", "ceiling.tga" };



//菜單欄選擇
void ProcessMenu(int value)
{
   
    GLint i ;
    for (i = 0 ; i<TEXTURE_COUNT; i++) {
        
        glBindTexture(GL_TEXTURE_2D, textures[i]);
        
        switch(value)
               {
                   case 0:
                      
                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
                       break;
                       
                   case 1:
                       
                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                       break;
                       
                   case 2:
                      
                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
                       break;
                       
                   case 3:
                    
                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
                       break;
                       
                   case 4:
                
                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
                       break;
                       
                   case 5:
                       
                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
                       break;
                       
                   case 6:
                   
                       //設(shè)置各向異性過濾
                       GLfloat fLargest;
                       //獲取各向異性過濾的最大數(shù)量
                       glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
                       //設(shè)置紋理參數(shù)(各向異性采樣)
                       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
                       break;
               
                   case 7:
                       //設(shè)置各向同性過濾,數(shù)量為1.0表示(各向同性采樣)
                       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
                       break;
                       
               }
    }
    glutPostRedisplay();
}


//在這個函數(shù)里能夠在渲染環(huán)境中進(jìn)行任何需要的初始化,它這里的設(shè)置并初始化紋理對象
void SetupRC()
{
    glClearColor(0, 0, 0, 1);
    shaderManager.InitializeStockShaders();
    
    
    
    GLbyte * byte;
    
    GLint i, width, height, iComponent;
    GLenum eFormat;
    
    glGenTextures(TEXTURE_COUNT, textures);
    for (i = 0; i<TEXTURE_COUNT; i++) {
        
        glBindTexture(GL_TEXTURE_2D, textures[i]);
        
        byte = gltReadTGABits(szTextureFiles[i], &width, &height, &iComponent, &eFormat);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        
        
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        
        glTexImage2D(GL_TEXTURE_2D, 0, iComponent, width, height, 0, eFormat, GL_UNSIGNED_BYTE, byte);
        glGenerateMipmap(GL_TEXTURE_2D);
        
        free(byte);
    }

    
    GLfloat z;
    floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    
    for (z = 60.0f; z >= 0.0f; z-= 10.0f) {
        
        floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        floorBatch.Vertex3f(-10.0f, -10.0f, z);
        
        floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        floorBatch.Vertex3f(10.0f, -10.0f, z);
        
        floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        floorBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
        
        floorBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        floorBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
    }
    floorBatch.End();
    
    ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for (z = 60.0f; z >= 0.0f; z-= 10.0f) {
        
        ceilingBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        ceilingBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
        
        ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        ceilingBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
        
        ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        ceilingBatch.Vertex3f(-10.0f, 10.0f, z);
        
        ceilingBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        ceilingBatch.Vertex3f(10.0f, 10.0f, z);
    }
    ceilingBatch.End();
    
    leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for (z = 60.0f; z >= 0.0f; z-= 10.0f) {
        
        leftWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        leftWallBatch.Vertex3f(-10.0f, -10.0f, z);
        
        leftWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        leftWallBatch.Vertex3f(-10.0f, 10.0f, z);
        
        leftWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        leftWallBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
        
        leftWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        leftWallBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
    }
    leftWallBatch.End();
    
    rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for (z = 60.0f; z >= 0.0f; z-=10.0f) {
        
        rightWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        rightWallBatch.Vertex3f(10.0f, -10.0f, z);
        
        rightWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        rightWallBatch.Vertex3f(10.0f, 10.0f, z);
        
        rightWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        rightWallBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
        
        rightWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        rightWallBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
        
    }
    rightWallBatch.End();
}

//關(guān)閉渲染環(huán)境
void ShutdownRC(void)
{
    glDeleteTextures(TEXTURE_COUNT, textures);
}


//前后移動視口來對方向鍵作出響應(yīng)
void SpecialKeys(int key, int x, int y)
{
    if (key == GLUT_KEY_UP) {
        viewZ += 0.5f;
    }
    if (key == GLUT_KEY_DOWN) {
        viewZ -= 0.5f;
    }
    glutPostRedisplay();
}

//改變視景體和視口,在改變窗口大小或初始化窗口調(diào)用
void ChangeSize(int w, int h)
{
    if (h == 0) h = 1;
    
    glViewport(0, 0, w, h);
    
    viewFrustum.SetPerspective(80, float(w)/float(h), 1, 120);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

//調(diào)用,繪制場景
void RenderScene(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    modelViewMatrix.PushMatrix();
    modelViewMatrix.Translate(0, 0, viewZ);
    
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE,transformPipeline.GetModelViewProjectionMatrix(),0);
    
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_FLOOR]);
    floorBatch.Draw();
    
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_CEILING]);
    ceilingBatch.Draw();
    
    glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
    leftWallBatch.Draw();
    rightWallBatch.Draw();
    
    modelViewMatrix.PopMatrix();
    glutSwapBuffers();
}



int main(int argc, char *argv[])
{
    gltSetWorkingDirectory(argv[0]);
    
    // 標(biāo)準(zhǔn)初始化
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(800, 600);
    glutCreateWindow("Tunnel");
    glutReshapeFunc(ChangeSize);
    glutSpecialFunc(SpecialKeys);
    glutDisplayFunc(RenderScene);
    
    // 添加菜單入口,改變過濾器
    glutCreateMenu(ProcessMenu);
    glutAddMenuEntry("GL_NEAREST",0);
    glutAddMenuEntry("GL_LINEAR",1);
    glutAddMenuEntry("GL_NEAREST_MIPMAP_NEAREST",2);
    glutAddMenuEntry("GL_NEAREST_MIPMAP_LINEAR", 3);
    glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 4);
    glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5);
    glutAddMenuEntry("Anisotropic Filter", 6);
    glutAddMenuEntry("Anisotropic Off", 7);
    
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    
    
    // 啟動循環(huán),關(guān)閉紋理
    SetupRC();
    glutMainLoop();
    ShutdownRC();
    
    return 0;
}

紋理坐標(biāo)對應(yīng)如下:


image.png

總結(jié):

1.讀取的紋理可以翻轉(zhuǎn)使用,正反面都可以用來填充。
2.繪制流程:指定生成紋理ID的數(shù)量和數(shù)組 —>綁定紋理ID—>讀取.tga文件載入紋理 —>設(shè)置過濾方式和環(huán)繞 —> 設(shè)置紋理和頂點(diǎn)對應(yīng)關(guān)系 —> 綁定相應(yīng)的紋理并用對應(yīng)的批次類繪制
3.修改紋理環(huán)繞過濾方式前,也需要綁定紋理ID

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容