Qt实现OpenGL的经典教程③——加载纹理

本帖将参考LearnOpenGL这一经典教程,使用Qt的原生环境完成教程中所提的所有流程,并尽量和原教程保持一致,如有错误,欢迎评论!

为了方便大家参考,我将项目分享至了gitee,并实时进行更行:Qt实现OpenGL的经典教程: (gitee.com)

教程中文网站:LearnOpenGLCN 

教程原网站:LearnOpenGL

Qt版本:6.7

操作系统:Windows10

Qt原生实现VAO、VBO和EBO对象

突然发现qt封装了QOpenGLBuffer和QOpenGLVertexArrayObject来实现VBO和VAO,这里对之前的代码进行修改,使用Qt封装好的对象来实现VAO,VBO和EBO三个对象,对MyOpenGLWidget.h代码修改如下:

#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H

#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>


class MyOpenGLWidget : public QOpenGLWidget, public QOpenGLFunctions_3_3_Core
{
public:
    MyOpenGLWidget();
    ~MyOpenGLWidget();

protected:
    void initializeGL();
    void resizeGL(int width, int height);
    void paintGL();

private:
    QOpenGLShaderProgram *_shaderProgram;
    QOpenGLTexture *_texture;
    QOpenGLVertexArrayObject *_vao;
    QOpenGLBuffer *_vbo;
    QOpenGLBuffer *_ebo;
};

#endif // MYOPENGLWIDGET_H

在类的成员中分别添加了几个相应的对象指针,由上到下分别为shader程序,纹理对象,vao,vbo,ebo。

Qt原生实现Texture纹理对象

qt的QOpenGLTexture 类封装了对opengl纹理的加载与绑定操作,上文中,我们已经声明了一个它的类成员来,它的主要代码逻辑如下所示:

    _texture = new QOpenGLTexture(QImage(":/container.jpg").mirrored());
    _texture->setWrapMode(QOpenGLTexture::Repeat);
    _texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
    _texture->setMagnificationFilter(QOpenGLTexture::Linear);
    _texture->generateMipMaps();
  • 上述代码第一行实现了图像数据的读取,不用再像LearnOpenGL中一样使用stb_image的库来读取图像了。
  • 第二行设置了纹理环绕方式为重复。
  • 第三行和第四行分别设置了缩小和放大的纹理过滤方式,都为线性过滤。
  • 第五行设置了生成多级渐远纹理。

实现纹理加载

我们加载了纹理对象,并设置了纹理环绕和过滤方式,此时我们的MyOpenGLWidget.cpp内容如下:

#include "myopenglwidget.h"
#include <QTime>
#include <QImage>

MyOpenGLWidget::MyOpenGLWidget()
{
    //设置上下文属性
    QSurfaceFormat format;
    format.setDepthBufferSize(24);
    format.setStencilBufferSize(8);
    format.setVersion(3, 3); //OpenGL 版本号3.3
    format.setProfile(QSurfaceFormat::CoreProfile);// 核心模式
    this->setFormat(format);
 }

MyOpenGLWidget::~MyOpenGLWidget()
{
    // Make sure the context is current and then explicitly
    // destroy all underlying OpenGL resources.
    makeCurrent();

    delete _texture;
    delete _shaderProgram;
    delete _vao;
    delete _vbo;
    delete _ebo;

    _vbo->destroy();
    _vao->destroy();
    _ebo->destroy();
    _texture->destroy();

    doneCurrent();
}

void MyOpenGLWidget::initializeGL()
{
    //绑定OpenGL函数指针?类似GLAD库的作用?
    initializeOpenGLFunctions();

    _shaderProgram = new QOpenGLShaderProgram;
    _shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertex.vert");
    _shaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragment.frag");
    //链接
    if(!_shaderProgram->link()){
        qDebug() << "link failed!\n";
    }

    float vertices[] = {
        // positions          // colors           // texture coords
        0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f,   1.0f, 1.0f, // top right
        0.5f, -0.5f, 0.0f,   0.0f, 1.0f, 0.0f,   1.0f, 0.0f, // bottom right
        -0.5f, -0.5f, 0.0f,   0.0f, 0.0f, 1.0f,   0.0f, 0.0f, // bottom left
        -0.5f,  0.5f, 0.0f,   1.0f, 1.0f, 0.0f,   0.0f, 1.0f  // top left
    };
    unsigned int indices[] = {
        0, 1, 3, // first triangle
        1, 2, 3  // second triangle
    };

    _vao = new QOpenGLVertexArrayObject();
    _vao->create();
    _vao->bind();

    _vbo = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
    _vbo->create();
    if(!_vbo->bind()){
        qDebug() << "vbo绑定失败!";
    }
    _vbo->allocate(vertices, sizeof(vertices));

    _ebo = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
    _ebo->create();
    if(!_ebo->bind()){
        qDebug() << "ebo绑定失败!";
    }
    _ebo->allocate(indices, sizeof(indices));

    // position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    // color attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
    // texture coord attribute
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
    glEnableVertexAttribArray(2);

    //创建对象
    _texture = new QOpenGLTexture(QImage(":/container.jpg").mirrored());
    _texture->setWrapMode(QOpenGLTexture::Repeat);
    _texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
    _texture->setMagnificationFilter(QOpenGLTexture::Linear);
    _texture->generateMipMaps();
}

void MyOpenGLWidget::paintGL()
{
    //由于继承了QOpenGLFunctions,可以直接使用OpenGL中的函数
    // render
    // ------
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    // bind Texture
    _texture->bind();

    // update shader uniform
    _shaderProgram->bind();

    // render the triangle
    _vao->bind();
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

}

void MyOpenGLWidget::resizeGL(int width, int height) {
    // OpenGL渲染窗口的尺寸大小,glViewport可以设置位置和宽高
    //    glViewport(0, 0, w, h);
    Q_UNUSED(width);
    Q_UNUSED(height);

    const qreal retinaScale = devicePixelRatio();
    glViewport(0, 0, this->width() * retinaScale, this->height() * retinaScale); //视口的宽度和高度将根据设备的像素比例进行缩放
}

接着,按照LearnOpenGL中的教程,我们对我们的顶点着色器和片段着色器进行修改:

#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;

out vec3 ourColor;
out vec2 TexCoord;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    ourColor = aColor;
    TexCoord = aTexCoord;
}
#version 330 core
out vec4 FragColor;

in vec3 ourColor;
in vec2 TexCoord;

// texture sampler
uniform sampler2D texture1;

void main()
{
        FragColor = texture(texture1, TexCoord);
}

点击运行后,我们就能看到如下图像了!

完善析构函数

既然用了Qt的对象,那么我们定义一个析构函数,析构函数中按照Qt中的要求进行一个OpenGL上下文环境的释放:

MyOpenGLWidget::~MyOpenGLWidget()
{
    // Make sure the context is current and then explicitly
    // destroy all underlying OpenGL resources.
    makeCurrent();

    delete _texture;
    delete _shaderProgram;
    delete _vao;
    delete _vbo;
    delete _ebo;

    _vbo->destroy();
    _vao->destroy();
    _ebo->destroy();
    _texture->destroy();

    doneCurrent();
}

本篇项目代码

为了方便大家参考,我将项目分享至了gitee,并实时进行更行:Qt实现OpenGL的经典教程: 本项目将参考LearnOpenGL这一经典教程,使用Qt的原生环境完成教程中所提的所有流程,并尽量和原教程保持一致,如有错误,欢迎评论! (gitee.com)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值