上面一张我们已经做了铺垫及绘制一个以正方形为图元的立方体,所以本章只需要给每个面绑定不同的纹理,把摄像机的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校正
网友评论