OpenGL初探

第二十节—纹理隧道

2020-09-05  本文已影响0人  L_Ares

本文为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。

本节结束。

上一篇 下一篇

猜你喜欢

热点阅读