OpenGL代码学习(22)--绘制通道

摘要:
注意:您需要在使用OpenGL配置的编程环境中运行以下代码。可以参考环境配置文章:Mac项目上OpenGL配置下面的代码可以直接放在main中。cpp文件:#include“GLTools.h”#include”GLShaderManager.h“#include”GL Frustum.h“#包含”GLBatch.h“#包括”GLFrame.h“#

注意:需要在配置好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;
        }
    }
    // 触发渲染
    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);
    // 设置右键菜单弹出
    glutAttachMenu(GLUT_RIGHT_BUTTON);
    
    // GLEW 驱动程序初始化
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s
", glewGetErrorString(err));
        return 1;
    }
    
    // 程序初始化渲染环境
    SetupRC();
    
    // 运行循环
    glutMainLoop();
    
    // 程序释放资源
    ShutdownRC();
    
    return 0;
}

效果如下:

OpenGL代码学习(22)--绘制通道第1张

免责声明:文章转载自《OpenGL代码学习(22)--绘制通道》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇iOS-WKWebView的使用地图发布的几种服务的区别下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

环信集成时常见错误

1、官方文档是2.0+的介绍,里面的jar包名不同,所以导致内部的类所用的包名也不同个,集成时注意:        com.easemob.chat.EMChatService(2.0+) com.hyphenate.chat.EMChatService(3.0+) 2、application中初始化的时候注意:         EMChat.getIns...

Java Selenium3 WebDriver启动火狐、Chrome、IE,Edge浏览器的方法(一)

selenium3和selenium2没有太大的区别,就是精简了一些不用的东西,对浏览器的支持更好了,比如对高版本的浏览器(FireFox,Chrome,Edge等)可以完美的支持,不用受限于版本的问题 下面总结一下启动常用浏览器的方法 前提 安装好java的环境配置 新建一个maven工程 在maven的pom文件加入selenium的依赖包(版本可根...

第十章 数组和指针

一 数组 数组由一系列相同的元素构成。 告诉编译器需要一个数组的方式叫数组声明(array declaration),声明需要告诉编译器数组元素的个数和类型。  初始化 int main(void) {   int powers[8] = {1,2,4,8,16,32,64,128};  ... } 未初始化的数组元素值为内存中的实际值,此值是不确定...

面渣逆袭:HashMap追魂二十三问

大家好,我是老三。 HashMap作为我们熟悉的一种集合,可以说是面试必考题。简单的使用,再到原理、数据结构,还可以延伸到并发,可以说,就一个HashMap,能聊半个小时。 1.能说一下HashMap的数据结构吗? JDK1.7的数据结构是数组+链表,JDK1.7还有人在用?不会吧…… 说一下JDK1.8的数据结构吧: JDK1.8的数据结构是数组+链表+...

spring相关的问题和原因分析

1、Bean的初始化顺序导致的项目启动失败 现象:shua-video项目中引用了配置中台bp-config的SDK,然后在mq消息监听类中使用。如上使用方式,在waterService中引用了bp-config。在测试环境mq中没有消息消费时项目能正常启动,但在线上有消息消费时项目启动报错,提示找不到bp-config类。 @Component @Slf...

说下hangfire吧

最近因工作需要开发计划任务模块(严格来说应该是修改bug吧,其他同事负责的)接触到了Hangfire。早前听同事说hangfire有点坑,怀着好奇,趁这两天bug改的差不多了,在github上面down了hangfire源码,下面分享一下,自己读hangfire源码的一些理解,和工作中需要注意的地方。介绍大概分为以下几个部分吧。1.准备工作,2.简单使用,...