第二十节—纹理隧道

本文为L_Ares个人写作,包括图片皆为个人亲自操作,以任何形式转载请表明原文出处。

本节为代码,主要综合了之前的一些知识。绘制出一条带有纹理的隧道


//
//  main.cpp
//  10隧道
//
//  Created by EasonLi on 2020/9/4.
//  Copyright © 2020 EasonLi. All rights reserved.
//

#include <stdio.h>

#pragma mark - 引用类

//工具类。包含大多数的GLTool中类似C语言的函数
#include "GLTools.h"
//着色器管理器类,包含一些初级的操作
#include "GLShaderManager.h"
//参考帧。坐标等
#include "GLFrame.h"
//设置投影矩阵类
#include "GLFrustum.h"
//矩阵堆栈类
#include "GLMatrixStack.h"
//三角形批次类
#include "GLBatch.h"
//矩阵堆栈管道类
#include "GLGeometryTransform.h"

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

#pragma mark - 常用变量

//着色器管理器
GLShaderManager shaderManager;
//模型视图矩阵堆栈
GLMatrixStack modelViewMatrixStack;
//投影矩阵堆栈
GLMatrixStack projectionMatrixStack;
//视景体
GLFrustum viewFrustum;
//矩阵堆栈管理管道
GLGeometryTransform transformPipeline;

//三角形批次类
//地板的批次类
GLBatch floorBatch;
//天花板批次类
GLBatch ceilingBatch;
//左墙面
GLBatch leftWallBatch;
//右墙面
GLBatch rightWallBatch;

//深度值初始值
GLfloat viewZ = -65.f;

//纹理标识符号
//墙面
#define TEXTURE_BRICK 0
//地板
#define TEXTURE_FLOOR 1
//纹理天花板
#define TEXTURE_CEILING 2
//纹理数量
#define TEXTURE_COUNT 3
//纹理标记数组
GLuint nTextures[TEXTURE_COUNT];
//纹理名字数组
const char *textureName[TEXTURE_COUNT] = {"brick.tga","floor.tga","ceiling.tga"};

#pragma mark - 函数
//窗口第一次创建或者大小改变时调用
void ChangeSize(int w , int h)
{
    if (h == 0) {
        h = 1;
    }
    //设置视口大小
    glViewport(0, 0, w, h);
    //通过视景体来设置投影方式
    viewFrustum.SetPerspective(88.f, float(w)/float(h), 1.f, 160.f);
    //获取投影矩阵并放置到投影矩阵堆栈栈顶
    projectionMatrixStack.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //设置矩阵堆栈变换管道
    transformPipeline.SetMatrixStacks(modelViewMatrixStack, projectionMatrixStack);
    
}

/**
 将.tga文件加载成纹理
 函数功能包含了读取、加载、设置纹理
 参数:
 (1).minFilter:缩小过滤模式
 (2).maxFilter:放大过滤模式
 (3).wrapMode:环绕方式
*/
bool LoadMyTextures (GLenum minFilter,GLenum maxFilter,GLenum wrapMode)
{
    //读取tga文件返回的是字节类型的纹理的数据,所以定义一个字节类型变量
    GLbyte *nByte;
    //定义变量:宽、高、每个纹理单元存储的颜色成分数量
    int nWidth,nHeight,nComponent;
    //定义变量:载入纹理要用的像素模式
    GLenum nFormat;
    
    //生成纹理标记,分配纹理对象
    glGenTextures(TEXTURE_COUNT, nTextures);
    
    //利用循环设置纹理数组中的各纹理的参数
    for (int i = 0; i < TEXTURE_COUNT; i++) {
        
        //绑定纹理对象
        glBindTexture(GL_TEXTURE_2D, nTextures[i]);
        
        //加载.tga文件
        nByte = gltReadTGABits(textureName[i], &nWidth, &nHeight, &nComponent, &nFormat);
        
        if (nByte == NULL) {
            return false;
        }
        
        //设置纹理过滤模式和环绕模式
        //纹理过滤器,放大过滤
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, maxFilter);
        //缩小过滤
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
        
        //设置环绕模式
        //S轴环绕,横向轴
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
        //T轴环绕,纵向轴
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
        
        //载入纹理
        glTexImage2D(GL_TEXTURE_2D, 0, nComponent, nWidth, nHeight, 0, nFormat, GL_UNSIGNED_BYTE, nByte);
        
        //为纹理生成一组mipmap
        glGenerateMipmap(GL_TEXTURE_2D);
        
        //释放纹理原始数据
        free(nByte);
        
    }
    
    return true;
}

//绘制地板
//depth:地板多长,就是地板深度
void DrawFloor (GLfloat depth)
{
    
    //设置地板的三角形批次类
    //参数:
    //(1).绘制地板要用的图元类型
    //(2).绘制地板要多少顶点
    //(3).要用到几组纹理坐标
    floorBatch.Begin(GL_TRIANGLE_STRIP, 28,1);
    
    //利用循环画地板
    for (GLfloat z = depth; z >= 0.f; z-=10.f) {
        
        //设置纹理坐标和顶点坐标
        floorBatch.MultiTexCoord2f(0, 0.f, 0.f);
        floorBatch.Vertex3f(-10.f, -10.f, z);
        
        floorBatch.MultiTexCoord2f(0, 1.f, 0.f);
        floorBatch.Vertex3f(10.f, -10.f, z);
        
        floorBatch.MultiTexCoord2f(0, 0.f, 1.f);
        floorBatch.Vertex3f(-10.f, -10.f, z - 10.f);
        
        floorBatch.MultiTexCoord2f(0, 1.f, 1.f);
        floorBatch.Vertex3f(10.f, -10.f, z - 10.f);
        
    }
    
    floorBatch.End();
    
}

//绘制天花板
void DrawCeiling (GLfloat depth)
{
    
    //设置天花板三角形批次类
    ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28,1);
    for (GLfloat z = depth; z >= 0.f; z-=10.f) {
        
        ceilingBatch.MultiTexCoord2f(0, 0.f, 0.f);
        ceilingBatch.Vertex3f(-10.f, 10.f, z);
        
        ceilingBatch.MultiTexCoord2f(0, 0.f, 1.f);
        ceilingBatch.Vertex3f(-10.f, 10.f, z - 10.f);
        
        ceilingBatch.MultiTexCoord2f(0, 1.f, 0.f);
        ceilingBatch.Vertex3f(10.f, 10.f, z);
        
        ceilingBatch.MultiTexCoord2f(0, 1.f, 1.f);
        ceilingBatch.Vertex3f(10.f, 10.f, z - 10.f);
        
    }
    ceilingBatch.End();
    
}

//绘制左墙面
void DrawLeftWall (GLfloat depth)
{
    
    leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28,1);
    for (GLfloat z = depth; z >= 0.f; z-=10.f) {
        
        leftWallBatch.MultiTexCoord2f(0, 0.f, 0.f);
        leftWallBatch.Vertex3f(-10.f, -10.f, z);
        
        leftWallBatch.MultiTexCoord2f(0, 0, 1.f);
        leftWallBatch.Vertex3f(-10.f, 10.f, z);

        leftWallBatch.MultiTexCoord2f(0, 1.f, 0.f);
        leftWallBatch.Vertex3f(-10.f, -10.f, z - 10.f);

        leftWallBatch.MultiTexCoord2f(0, 1.f, 1.f);
        leftWallBatch.Vertex3f(-10.f, 10.f, z - 10.f);
        
    }
    leftWallBatch.End();
    
}

//绘制右墙面
void DrawRightWall (GLfloat depth)
{
    
    rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28.f,1);
    for (GLfloat z = depth; z >= 0.f; z-=10) {
        
        rightWallBatch.MultiTexCoord2f(0, 0.f, 0.f);
        rightWallBatch.Vertex3f(10.f, -10.f, z);
        
        rightWallBatch.MultiTexCoord2f(0, 0, 1.f);
        rightWallBatch.Vertex3f(10.f, 10.f, z);
        
        rightWallBatch.MultiTexCoord2f(0, 1.f, 0.f);
        rightWallBatch.Vertex3f(10.f, -10.f, z - 10.f);
        
        rightWallBatch.MultiTexCoord2f(0, 1.f, 1.f);
        rightWallBatch.Vertex3f(10.f, 10.f, z - 10.f);
        
        
    }
    rightWallBatch.End();
    
}

//设置渲染环境
void SetUpRC ()
{
    
    //设置清屏颜色
    glClearColor(0.0f, 0.0f, 0.0f, 1.f);
    //初始化着色器管理器
    shaderManager.InitializeStockShaders();
    
    bool result;
    
    //设置纹理信息
    result = LoadMyTextures(GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE);
    
    if (result) {
        //绘制地板
        DrawFloor(60.f);
        //绘制天花板
        DrawCeiling(60.f);
        //绘制左墙面
        DrawLeftWall(60.f);
        //绘制右墙面
        DrawRightWall(60.f);
        
    }else{
        printf("读取不到纹理");
    }
    
    
}

//渲染
void RenderScene ()
{
    
    //清空缓冲区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    //压栈
    modelViewMatrixStack.PushMatrix();
    modelViewMatrixStack.Translate(0.f, 0.f, viewZ);
    
    //设置着色器
    //地板
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE,transformPipeline.GetModelViewProjectionMatrix(),0);
    //绑定纹理
    glBindTexture(GL_TEXTURE_2D, nTextures[TEXTURE_FLOOR]);
    //地板绘制
    floorBatch.Draw();
    
    //天花板
    glBindTexture(GL_TEXTURE_2D, nTextures[TEXTURE_CEILING]);
    ceilingBatch.Draw();
    
    //左侧墙面
    glBindTexture(GL_TEXTURE_2D, nTextures[TEXTURE_BRICK]);
    leftWallBatch.Draw();
    rightWallBatch.Draw();
    
    //出栈
    modelViewMatrixStack.PopMatrix();
    
    //交换缓冲区
    glutSwapBuffers();
    
}

//特殊键位
void SpecialKeys (int key , int x , int y)
{
    
    switch (key) {
        case GLUT_KEY_UP:
            viewZ += 1.f;
            break;
            
        case GLUT_KEY_DOWN:
            viewZ -= 1.f;
            break;
    }
    glutPostRedisplay();
    
    
}

//右键选择
void RightButtonMenu (int value)
{
    
    for (int i = 0; i < TEXTURE_COUNT; i++) {
        //更改纹理前,记得绑定纹理,OpenGL这才会知道你要修改哪个纹理
        glBindTexture(GL_TEXTURE_2D, nTextures[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:
                //设置各向异性过滤
                //定义变量存储各向异性过滤的最大数量
                GLfloat fMax;
                //获取各向异性过滤最大数量
                glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fMax);
                //设置纹理参数
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fMax);
                break;
                
            case 7:
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
                break;
                
        }
    }
    
    glutPostRedisplay();
    
}

//关闭纹理
void ShutDownTexture ()
{
    
    glDeleteTextures(TEXTURE_COUNT, nTextures);
    
}

#pragma mark - main
int main (int argc,char *argv[])
{
    
    //设置工作目录和项目目录在同一文件夹下/Resource
    //glut的初始化已经设置过了,手动保证安全
    gltSetWorkingDirectory(argv[0]);
    
    //glut初始化
    glutInit(&argc, argv);
    
    //初始化显示模式
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    
    //初始化窗口大小
    glutInitWindowSize(600, 600);
    
    //创建窗口并命名
    glutCreateWindow("隧道");
    
    //注册函数
    //重塑函数
    glutReshapeFunc(ChangeSize);
    //渲染函数
    glutDisplayFunc(RenderScene);
    //特殊键位函数
    glutSpecialFunc(SpecialKeys);
    
    //右键菜单栏
    glutCreateMenu(RightButtonMenu);
    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);
    
    //初始化glew库
    GLenum status = glewInit();
    if (status != GLEW_OK) {
        printf("glew init error : %s \n",glewGetErrorString(status));
        return 1;
    }
    
    //设置渲染环境
    SetUpRC();
    
    //建立本地信息循环
    glutMainLoop();
    
    //关闭纹理
    ShutDownTexture();
    
    return 0;
    
}


效果图如下图1.1所示:

1.1.png

纹理的.tga文件在这里:
纹理tga文件
提取码:uhtv。

本节结束。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351