OpenGL-隧道案例分析

2020-10-17 15:47:52 蜻蜓队长

本次案例分析我们主要实现改动画


我们要实现这样的效果,需要绘制四个纹理,左右墙面纹理,隧道顶部以及底部纹理

准备工作

同样我们整体的顺序是ChangeSize函数->SetupRC函数->RenderScene函数,以及控制视图的SpecialKeys函数

ChangeSize函数

ChangeSize函数主要还是设置窗口、投影矩阵、加载投影矩阵以及设置变换管道,代码如下

void ChangeSize(int w,int h)
{
    if (h == 0) {
        h = 1;
    }
    glViewport(0,0, w, h);
    //设置投影矩阵
    viewFrustum.SetPerspective(100.0f, (float)w/(float)h, 1.0, 120.0);
    //加载投影矩阵
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //设置变换管道
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

复制代码

SetupRC函数

这个函数里面处理的事情主要是设置背景色、初始化着色器管理、处理三个(上、下跟左右)纹理,设置纹理跟隧道顶点的映射关系

设置背景以及初始化着色管理器

//设置背影颜色
    glClearColor(0.0f,0.0f,0.0f,1.0f);
    //初始化着色管理器
    shaderManager.InitializeStockShaders();

复制代码

处理纹理

GLbyte *pBytes;
    GLint iWidth, iHeight, iComponents;
    GLenum eFormat;
    GLint iLoop;
    //生成纹理标记
    glGenTextures(TEXTURE_COUNT, textures);
    //for循环设置纹理
    for (int i = 0; i<TEXTURE_COUNT; i++) {
        //绑定纹理
        glBindTexture(GL_TEXTURE_2D, textures[i]);
        //解析tga文件
        pBytes = gltReadTGABits(szTextureFiles[i], &iWidth, &iHeight, &iComponents, &eFormat);
        //设置纹理过滤方式
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);//放大过滤
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);//缩小过滤
        //设置环绕方式
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        
        //加载纹理
        glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
        //生成完整的mip贴图
        glGenerateMipmap(GL_TEXTURE_2D);
        
        //释放纹理数据
        free(pBytes);
    }

复制代码

处理地板纹理与顶点映射关系

如下图所示,地板顶点的变化主要是z轴发生了变化


//z表示隧道的深度,z的值约小距离屏幕越远
    GLfloat z;
    floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for (z = 70.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();

复制代码

设置顶部纹理与顶点关系

同样我们从下图可以看到顶点变化的依然是z轴


//绘制天花板
    ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for(z = 70.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();

复制代码

设置左侧墙面纹理与顶点的映射关系

如下图所示


//绘制左侧墙面
    leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
    for(z = 70.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 = 70.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();

复制代码

RenderScene函数

主要就是根据纹理绘制隧道

void RenderScene(void)
{
    //清除一个或一组特定的缓冲区
    
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    
    //模型视图压栈
    modelViewMatrix.PushMatrix();
    //视图平移
    modelViewMatrix.Translate(0, 0, 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();
}


复制代码

SpecialKeys函数

主要是接手上下左右键的输入并重新绘制隧道

//前后移动视口来对方向键作出响应
void SpecialKeys(int key, int x, int y)
{
    if(key == GLUT_KEY_UP)
        //移动的是深度值,Z
        viewZ += 0.5f;
    
    if(key == GLUT_KEY_DOWN)
        viewZ -= 0.5f;
    
    //更新窗口,即可回调到RenderScene函数里
    glutPostRedisplay();
}
复制代码

main函数

程序入口

int main(int argc,char* argv[])
{
    gltSetWorkingDirectory(argv[0]);
    // 标准初始化
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(800, 600);
    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);
    
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    
    
    // 启动循环,关闭纹理
    SetupRC();
    glutMainLoop();
    ShutdownRC();
    
    return 0;
}


复制代码


以上内容来自于网络,如有侵权联系即删除
相关文章

上一篇: Android Q & Android 11存储适配(二) FileOperator文件管理框架

下一篇: vscode配置使vue项目支持断点调试

客服紫薇:15852074331
在线咨询
客户经理