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