QT+OpenGL六之天空盒

上面一张我们已经做了铺垫及绘制一个以正方形为图元的立方体,所以本章只需要给每个面绑定不同的纹理,把摄像机的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 
#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;
    vectormTexture;
    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六之天空盒)