OpenGL绘制隧道

331 阅读3分钟

如何使用OpenGL绘制如下的隧道效果???

#include "GLTools.h"
#include <GLUT/GLUT.h>
#include "GLShaderManager.h"
#include "GLFrustum.h"
#include "GLMatrixStack.h"
#include "GLGeometryTransform.h"

#define TEXTURE_BRICK 0//墙面
#define TEXTURE_FLOOR 1//地板
#define TEXTURE_CEILING 2 //天花板
#define TEXTURE_COUNT  3 //纹理数量

GLuint textures[TEXTURE_COUNT];//纹理标记数组

//投影方式
GLFrustum viewFrustum;
//投影矩阵
GLMatrixStack projectionMatrix;
//变换管道
GLGeometryTransform transformPipeline;
//模型视图矩阵
GLMatrixStack modelViewMatrix;

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

//固定着色器管理者
GLShaderManager shaderManager;
GLBatch             floorBatch;//地面
GLBatch             ceilingBatch;//天花板
GLBatch             leftWallBatch;//左墙面
GLBatch             rightWallBatch;//右墙面

const char *szTextureFiles[TEXTURE_COUNT] = { "brick.tga", "floor.tga", "ceiling.tga" };


void ChangeSize(int w,int h){
    //设置窗口大小
    glViewport(0, 0, w, h);
    
    GLfloat fAspect = (GLfloat)w/(GLfloat)h;
    //设置投影方式
    viewFrustum.SetPerspective(80.0f, fAspect, 1.0f, 120.0f);
    //将投影方式载入投影矩阵
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //将模型视图矩阵和投影矩阵载入变换管道
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
void RenderScene(){
    glClear(GL_COLOR_BUFFER_BIT);
    
    //模型视图压栈
    modelViewMatrix.PushMatrix();
    //z轴平移一定距离
    modelViewMatrix.Translate(0.0f, 0.0f, viewZ);
    //纹理替换矩阵着色器
   /*
    参数一:GLT_SHADER_TEXTURE_REPLACE着色器类型
    参数二:模型视图投影矩阵
    参数三:纹理层
    */ 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 SetupRC(){
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    shaderManager.InitializeStockShaders();
    
    //分配纹理对象
    glGenTextures(TEXTURE_COUNT, textures);
    //定义一些变量,来接收纹理数据信息
    GLbyte *pBytes;
    GLint iWidth,iHeight,iComponents;
    GLenum eFormat;
    GLint iLoop;
    for (iLoop = 0; iLoop<TEXTURE_COUNT; iLoop++) {
        //绑定纹理
        /*
         参数一:纹理模式GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D,
         参数二:需要绑定的纹理对象
         */
        glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
        
        //加载tga文件
        /*
         参数一:文件名称
         参数二:接收图片的宽
         参数三:接收图片的高
         参数四:接收图片组件
         参数五:接收文件格式
         返回值:pBytes指向图像数据的指针
         */
        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_LINEAR);
        
        //设置环绕方式
        ///S(X)轴方向采用拉伸边缘的环绕模式
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        //T(Y)轴方向采用拉伸边缘的环绕模式
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        
        //载入纹理
        /*
         参数一:纹理模式
         参数二:mip贴图层次
         参数三:纹理颜色
         参数四:宽度
         参数五:高度
         参数六:深度
         参数七:像素的数据类型,一般用GL_UNSIGNED_BYTE,表示无符号整型
         参数八:指向纹理数据的指针
         */
        glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
        
        //生成纹理贴图
        glGenerateMipmap(GL_TEXTURE_2D);
        
        //释放
        free(pBytes);
    }
    
    //设置顶点数据
    GLfloat z;//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();
    
    //参考PPT图6-11
     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();
     
     //参考PPT图6-12
     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();
    
    //参考PPT图6-13
     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 shutdownRC(){
    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 ProcessMenu(int value){
    for (int 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:
            {
                //缩小,选择最邻近的Mip层,并执行最邻近过滤
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
            }
                break;
            case 3:
            {
                //缩小,在Mip层之间执行线性插补,并执行邻近过滤
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
            }
                break;
            case 4:
            {
                //缩小,选择最邻近Mip层,并执行线性过滤
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
            }
                break;
            case 5:
            {
                //缩小,在Mip层之间执行线性插补,并执行线性过滤,又称为三线性过滤
                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:
            {
                //设置各向同性过滤,数量为1.0表示各向同性采样
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
            }
                break;
            default:
                break;
        }
    }
  
    //
    glutPostRedisplay();
}

int main(int argc, char *argv[]){
    
    gltSetWorkingDirectory(argv[0]);
    //
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    //
    glutInitWindowSize(800, 600);
    glutCreateWindow("Tunnel");
    //
    glutReshapeFunc(ChangeSize);
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);
    //添加菜单入口
    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));
    }
    
    SetupRC();
    glutMainLoop();
    
    //删除纹理
    shutdownRC();
    
    return 0;
}