美文网首页my-QT专栏
QT+OpenGL六之天空盒

QT+OpenGL六之天空盒

作者: c之气三段 | 来源:发表于2021-04-01 12:03 被阅读0次

    上面一张我们已经做了铺垫及绘制一个以正方形为图元的立方体,所以本章只需要给每个面绑定不同的纹理,把摄像机的location位置当作天空盒的模型矩阵传入即可。

    上一章的代码中虽然进行了优化但是,我们会发现每个模型对象在加载的时候都重新设置了一次投影矩阵,这是没有必要的,因为是同一个shader程序设置一次就可以了。,调整shader在我们需要时才使用以保证程序无错且提高效率。

    1.把每个模型设置投影矩阵的部分抽取到shader类中

    MyShader.h

    #pragma once
    class MyShader
    {
    public:
        void creatShader(const QString vsName, const QString fsName);
        QOpenGLShaderProgram* getShader();
    //添加一个设置投影矩阵的函数
        void setPerspective(float verticalAngle,int windowWidth,int windowHeight,float minimumSight,float farthestSight);
    private:
        QOpenGLShaderProgram shaderProgram;
    };
    

    MyShader.cpp

    #include "stdafx.h"
    #include "MyShader.h"
    void MyShader::creatShader(const QString vsName, const QString fsName) {
        if (!shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, vsName)) {     //添加并编译顶点着色器
            qDebug() << "编译ERROR:" << shaderProgram.log();    //如果编译出错,打印报错信息
        }
        if (!shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, fsName)) {   //添加并编译片段着色器
            qDebug() << "编译ERROR:" << shaderProgram.log();    //如果编译出错,打印报错信息
        }
        if (!shaderProgram.link()) {                      //链接着色器
            qDebug() << "链接ERROR:" << shaderProgram.log();    //如果链接出错,打印报错信息
        }
    }
    QOpenGLShaderProgram *MyShader::getShader() {
        return &shaderProgram;
    }
    void MyShader::setPerspective(float verticalAngle, int windowWidth, int windowHeight, float minimumSight, float farthestSight) {
        shaderProgram.bind();
        float aspect = (float)windowWidth / (float)windowHeight;
        QMatrix4x4 pMat;
        pMat.perspective(verticalAngle, aspect, minimumSight, farthestSight);
        shaderProgram.setUniformValue("proj_matrix", pMat);
        shaderProgram.release();
    }
    

    注意这里就不贴三角形图元立方体类中的修改,和天空盒类似,只是不动他的模型矩阵
    天空盒图片提取:
    链接:https://pan.baidu.com/s/1NNaQPCjIPKy0Vp4tgSPreQ
    提取码:jsdd
    复制这段内容后打开百度网盘手机App,操作更方便哦
    SkyBox.h

    #pragma once
    #include <qopenglfunctions_4_3_core.h>
    #include "Camera.h"
    #include"vector"
    using namespace std;
    class SkyBox : protected QOpenGLFunctions_4_3_Core
    {
    public:
        SkyBox();
        ~SkyBox();
        void init(QOpenGLShaderProgram* shaderProgram);
        void draw(Camera camera);
    private:
        GLuint vPosition, uvlo;
        QOpenGLShaderProgram* shaderProgram;
        vector<QOpenGLTexture*>mTexture;
        QMatrix4x4 pMat,mvMat;
        QOpenGLVertexArrayObject vao;
        QOpenGLBuffer vbo, uvVbo;
        void setupVertices();
    };
    

    SkyBox.cpp

    #include "stdafx.h"
    #include "SkyBox.h"
    SkyBox::SkyBox() {
       mTexture.reserve(6);
    }
    SkyBox::~SkyBox() {
        vbo.destroy();
        uvVbo.destroy();
        mTexture.clear();
    }
    void SkyBox::init(QOpenGLShaderProgram* shaderProgram) {
        initializeOpenGLFunctions();
        this->shaderProgram = shaderProgram;
        setupVertices();
    //在vector向量中写入六张纹理分别是前后左右上下
        mTexture.push_back(new QOpenGLTexture(QImage(":/skyBox/Resources/skyBox/front.bmp").mirrored()));
        mTexture.push_back(new QOpenGLTexture(QImage(":/skyBox/Resources/skyBox/back.bmp").mirrored()));
        mTexture.push_back(new QOpenGLTexture(QImage(":/skyBox/Resources/skyBox/left.bmp").mirrored()));
        mTexture.push_back(new QOpenGLTexture(QImage(":/skyBox/Resources/skyBox/right.bmp").mirrored()));
        mTexture.push_back(new QOpenGLTexture(QImage(":/skyBox/Resources/skyBox/top.bmp").mirrored()));
        mTexture.push_back(new QOpenGLTexture(QImage(":/skyBox/Resources/skyBox/bottom.bmp").mirrored()));
        for (int i = 0; i < 6; i++) {//每张纹理都设置为边缘线性过滤。消除边缘缝隙。
    //这和OpenGL原生的glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);//最后参数大于纹理坐标1.0的时候取1.0的颜色、换成GL_REPEAT大于1.0是取减去1.0的颜色
        //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);相对应的
            mTexture[i]->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
            mTexture[i]->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
        }
    }
    void SkyBox::setupVertices() {
        GLfloat vertexPositions[72] = {
           -0.5,-0.5,-0.5,0.5,-0.5,-0.5,0.5,0.5,-0.5,-0.5,0.5,-0.5,
           0.5,-0.5,0.5,-0.5,-0.5,0.5,-0.5,0.5,0.5,0.5, 0.5, 0.5,
           -0.5,-0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5, -0.5,-0.5, 0.5,0.5,
           0.5,-0.5,-0.5,0.5,-0.5,0.5,0.5, 0.5,0.5,0.5, 0.5, -0.5,
           -0.5,0.5,-0.5,0.5,0.5,-0.5,0.5, 0.5,0.5,-0.5, 0.5, 0.5,
           -0.5,-0.5f, 0.5,0.5,-0.5, 0.5,0.5,-0.5,-0.5,-0.5,-0.5,-0.5
        };
        GLfloat uv[48] = {
        0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,0.0f,1.0f,
        0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,0.0f,1.0f,
        0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,0.0f,1.0f,
        0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,0.0f,1.0f,
        0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,0.0f,1.0f,
        0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,0.0f,1.0f,
        };
        vao.create();
        vbo.create();
        uvVbo.create();
        vao.bind();
        vbo.bind();
        vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
        vbo.allocate(vertexPositions, sizeof(vertexPositions));
        vPosition = shaderProgram->attributeLocation("vPosition");
        shaderProgram->setAttributeBuffer(vPosition, GL_FLOAT, 0, 3, 0);
        uvVbo.bind();
        uvVbo.allocate(uv, sizeof(uv));
        glEnableVertexAttribArray(vPosition);
        uvlo = shaderProgram->attributeLocation("inuv");
        shaderProgram->setAttributeBuffer(uvlo, GL_FLOAT, 0, 2, 0);
        glEnableVertexAttribArray(uvlo);
        vao.release();
    }
    void SkyBox::draw(Camera camera) {
        glDisable(GL_DEPTH_TEST);//关闭深度缓冲区,避免天空盒遮挡其他物体
        shaderProgram->bind();
        QMatrix4x4 mMat;//模型矩阵取摄像机的位置,避免逃出了天空盒
        mMat.translate(camera.location.x, camera.location.y, camera.location.z);
        QMatrix4x4 v;
        v.lookAt(QVector3D(camera.location.x, camera.location.y, camera.location.z),
            QVector3D(camera.viewPoint.x, camera.viewPoint.y, camera.viewPoint.z),
            QVector3D(camera.worldY.x, camera.worldY.y, camera.worldY.z));
        mvMat = v * mMat;
        shaderProgram->setUniformValue("mv_matrix", mvMat);
        //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
          for (int i = 0,j=0; i <= 20;j++) {//用循环来修改每个面的纹理
              mTexture.at(j)->bind(mTexture.at(j)->textureId());
              shaderProgram->setUniformValue("imgTexture", mTexture.at(j)->textureId());
            vao.bind();
            glDrawArrays(GL_QUADS, i, 4);
            vao.release();
            mTexture[j]->release();
          i =i+4;
        }
          shaderProgram->release();
    }
    

    最后QOpenGLWidget.cpp

    void MyOpenglWegdit::initializeGL()
    {
        initializeOpenGLFunctions();
        shader.creatShader(":/QtGuiApplication1/Resources/config/shader.vs", ":/QtGuiApplication1/Resources/config/shader.fs");
        shader.setPerspective(60.0f,width(),height(),0.1f,1000.0f);
        glShadeModel(GL_SMOOTH);//设置阴影平滑模式
        glClearColor(0.98, 0.625, 0.12, 0.5);//改变窗口的背景颜色
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);//进行透视校正
        sky.init(shader.getShader());
        cube.init(shader.getShader());
    }
    
    void MyOpenglWegdit::resizeGL()
    {
        glViewport(0, 0, width(), height());
    }
    
    void MyOpenglWegdit::paintGL()
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        updataDetlaTime();
        sky.draw(camera);
        glEnable(GL_DEPTH_TEST);
        glDepthFunc(GL_LEQUAL);
        cube.draw(camera);
        //glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
       QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
    }
    

    这里是不是就变得更简介了喃;
    动态图:


    1.gif

    目录

    VSC++2019+QT+OpenGL
    QT+OpenGL一之绘制立方体(三角形图元)
    QT+OpenGL二之纹理贴图
    QT+OpenGL三之矩阵简解
    QT+OpenGL四之相机的移动和旋转
    QT+OpenGL五之绘制不同的模型(vao,vbo机制)
    QT+OpenGL六之天空盒
    QT+OpenGL七之使用EBO
    QT+OPenGL八之模型准备
    QT+OPenGL九之模型解码
    QT+OPenGL十之光照模型
    QT+OPenGL十一之漫反射和镜面反射贴图
    QT+OPenGL十二之定向光
    QT+OPenGL十三之真正的点光源和聚光灯
    QT+OPenGL十四之多光源混合的问题
    QT+OPenGL十五之深度缓冲区
    QT+OPenGL十六之模板缓冲区
    QT+OPenGL十七帧缓冲区(离屏渲染)
    QT+OPenGL十八抗锯齿
    QT+OPenGL十九镜面反射效率调整
    QT+OPenGL二十Gamma校正

    相关文章

      网友评论

        本文标题:QT+OpenGL六之天空盒

        本文链接:https://www.haomeiwen.com/subject/vnhtkltx.html