OpenGL代码学习(23)--绘制通道中的更多处理

注意:需要在配置好OpenGL的编程环境中运行下列代码,环境配置文章可参考:

OpenGL在Mac项目上的配置

下面的代码,直接放置在main.cpp文件中即可:

#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;
// 视景体
GLFrustum viewFrustum;
// 变换管线,以及它管理的2个矩阵堆栈
GLGeometryTransform transformPipeline;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;

// 4个数据批次
GLBatch floorBatch;
GLBatch ceilingBatch;
GLBatch leftWallBatch;
GLBatch rightWallBatch;

// 用于控制观察者向前和向后
GLfloat viewZ = -65.0f;

// 宏定义,地板、天花板、墙分别对应的纹理标识数组索引
#define TEXTURE_BRICK   0
#define TEXTURE_FLOOR   1
#define TEXTURE_CEILING 2
#define TEXTURE_COUNT   3
// 纹理标识数组
GLuint  textures[TEXTURE_COUNT];
// 纹理文件名数组
const char *szTextureFiles[TEXTURE_COUNT] = { "brick.tga", "floor.tga", "ceiling.tga" };

// 点击右键菜单选项回调
void ProcessMenu(int value) {
    // 循环遍历所有纹理数据
    for(GLint iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) {
        // 绑定当前纹理为该索引对应的纹理数据
        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
        
        // 设置该纹理数据的缩小过滤器
        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 fLargest;
                glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
                break;
            case 7:
                // 设置各向同性
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
                break;
        }
    }
    // 触发渲染
    glutPostRedisplay();
}

// 加载所有的纹理数据
void LoadAllTextureData() {
    GLbyte *pBytes;
    GLint iWidth, iHeight, iComponents;
    GLenum eFormat;
    GLint iLoop;
    // 申请要加载的纹理数据数量
    glGenTextures(TEXTURE_COUNT, textures);
    // 循环遍历所有纹理文件
    for(iLoop = 0; iLoop < TEXTURE_COUNT; iLoop++) {
        // 绑定当前纹理为该索引对应的纹理数据
        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
        
        // 从 TGA 文件中读取纹理数据
        pBytes = gltReadTGABits(szTextureFiles[iLoop], &iWidth, &iHeight, &iComponents, &eFormat);
        
        // 设置纹理数据缩小、放大过滤器
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        
        // 设置纹理数据(s, t)环绕模式
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        
        // 加载纹理数据到2维纹理缓冲区
        glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
        
        // 2维纹理缓冲区开启 Mip 贴图
        glGenerateMipmap(GL_TEXTURE_2D);
        
        // 释放纹理数据
        free(pBytes);
    }
}

// 初始化地板数据
void SetupFloorBatch() {
    GLfloat z;
    floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for(z = 60.0f; z >= 0.0f; z -=10.0f) {
        floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        floorBatch.Vertex3f(-10.0f, -10.0f, z);
        
        floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        floorBatch.Vertex3f(10.0f, -10.0f, z);
        
        floorBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        floorBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
        
        floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        floorBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
    }
    floorBatch.End();
}

// 初始化天花板数据
void SetupCeilingBatch() {
    GLfloat z;
    ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for(z = 60.0f; z >= 0.0f; z -=10.0f) {
        ceilingBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        ceilingBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
        
        ceilingBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        ceilingBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
        
        ceilingBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        ceilingBatch.Vertex3f(-10.0f, 10.0f, z);
        
        ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        ceilingBatch.Vertex3f(10.0f, 10.0f, z);
    }
    ceilingBatch.End();
}

// 初始化左右墙数据
void SetupWallBatch() {
    // 左墙
    GLfloat z;
    leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for(z = 60.0f; z >= 0.0f; z -=10.0f) {
        leftWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
        leftWallBatch.Vertex3f(-10.0f, -10.0f, z);
        
        leftWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        leftWallBatch.Vertex3f(-10.0f, 10.0f, z);
        
        leftWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        leftWallBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
        
        leftWallBatch.MultiTexCoord2f(0, 1.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, 0.0f, 0.0f);
        rightWallBatch.Vertex3f(10.0f, -10.0f, z);
        
        rightWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
        rightWallBatch.Vertex3f(10.0f, 10.0f, z);
        
        rightWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
        rightWallBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
        
        rightWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
        rightWallBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
    }
    rightWallBatch.End();
}

// 程序初始化渲染环境
void SetupRC() {
    // 设置窗口背景为黑色
    glClearColor(0.0f, 0.0f, 0.0f,1.0f);
    
    // 初始化着色器
    shaderManager.InitializeStockShaders();
    
    // 加载所有纹理数据
    LoadAllTextureData();
    
    // 初始化地板
    SetupFloorBatch();
    // 初始化天花板
    SetupCeilingBatch();
    // 初始化墙
    SetupWallBatch();
}

// 程序释放资源
void ShutdownRC(void) {
    // 删除所有的纹理数据
    glDeleteTextures(TEXTURE_COUNT, textures);
}

// 特殊按键点击回调
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();
}

// 窗口渲染回调方法
void RenderScene(void) {
    // 清除缓冲区内容
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 压入单位矩阵
    modelViewMatrix.PushMatrix();
    // 模型视图向Z轴平移
    modelViewMatrix.Translate(0.0f, 0.0f, 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();
}

// 窗口大小变化回调方法
void ChangeSize(int width, int height) {
    // 防止除数为0
    if(height == 0)
        height = 1;
    
    // 设置视口
    glViewport(0, 0, width, height);
    // 计算窗口宽高比
    GLfloat fAspect = (GLfloat)width / (GLfloat)height;
    // 设置投影矩阵
    viewFrustum.SetPerspective(80.0f, fAspect, 1.0, 120.0);
    // 投影矩阵堆栈保持投影矩阵
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    // 设置变换管线的投影矩阵堆栈和模型视图矩阵堆栈
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    
}

// 程序入口
int main(int argc, char *argv[]) {
    // 设置 Mac OS 工作目录路径
    gltSetWorkingDirectory(argv[0]);
    
    // GLUT 初始化
    glutInit(&argc, argv);
    
    // 设置 GLUT 渲染模式
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    
    // 创建窗口
    glutInitWindowSize(800, 720);
    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);
    
    // GLEW 驱动程序初始化
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    
    // 程序初始化渲染环境
    SetupRC();
    
    // 运行循环
    glutMainLoop();
    
    // 程序释放资源
    ShutdownRC();
    
    return 0;
}

两个比较明显的对比图:

 

 

 

posted @ 2021-05-03 00:24  码出境界  阅读(137)  评论(0编辑  收藏  举报