使用QOpenGLWidget(调用GPU)渲染QImage加载的图片

网友投稿 2815 2022-05-29

一、OpenGL介绍

OpenGL是一个用来加速渲染显示2D、3D 矢量图形的编程接口。这个接口底层依赖于硬件GPU,底层硬件接口的驱动都是由GPU厂家提供。

openGl也支持跨平台,windows、Linux、MAC 平台都可以使用。

QT封装有QOpenGLWidget可以更加方便的调用GPU 来渲染图片。

下面例子代码就介绍QOpenGLWidget类的使用说明,并编写一个例子代码,调用GPU加速渲染一张QImage加载的图片。

二、QOpenGLWidget类介绍

下面是来至官方帮助的文档的介绍,我这里做了简单的调整,并翻译了一下:

QOpenGLWidget类是一个用于呈现OpenGL图形的小部件。

QOpenGLWidget提供了显示集成到Qt应用程序中的OpenGL图形的功能。它的使用非常简单:使你的类继承自它,并像任何其他QWidget一样使用子类,但你可以选择使用QPaint和标准OpenGL渲染命令。

QOpenGLWidget提供了三个方便的虚拟函数,你可以在子类中重新实现这些函数以执行典型的OpenGL任务:

使用QOpenGLWidget(调用GPU)渲染QImage加载的图片

paintGL()-渲染OpenGL场景。每当小部件需要更新时调用。

resizeGL()-设置OpenGL视口、投影等。每当小部件调整大小时(以及首次显示时,因为所有新创建的小部件都会自动获得调整大小事件),都会调用该小部件。

initializeGL()-设置OpenGL资源和状态。在第一次调用resizeGL()或paintGL()之前调用一次。

如果需要从paintGL()以外的位置触发重新绘制(典型示例是使用计时器设置场景动画),则应调用小部件的update()函数来安排更新。

调用paintGL()、resizeGL()或initializeGL()时,小部件的OpenGL呈现上下文将变为当前。如果需要从其他位置(例如,在小部件的构造函数或自己的绘制函数中)调用标准OpenGL API函数,则必须首先调用makeCurrent()。

所有渲染都发生在OpenGL帧缓冲区对象中。makeCurrent()确保它在上下文中绑定。在paintGL()中的渲染代码中创建和绑定其他帧缓冲区对象时,请记住这一点。永远不要重新绑定ID为0的帧缓冲区。相反,调用defaultFramebufferObject()获取应该绑定的ID。

QOpenGLWidget允许在平台支持时使用不同的OpenGL版本和配置文件。只需通过setFormat()设置请求的格式。但是请记住,在同一窗口中有多个QOpenGLWidget实例需要它们都使用相同的格式,或者至少使用不会使上下文不可共享的格式。要解决此问题,请首选使用QSurfaceFormat::setDefaultFormat()而不是setFormat()。

注意:在某些平台(例如macOS)上,当请求OpenGL核心概要文件上下文时,在构造QApplication实例之前调用QSurfaceFormat::setDefaultFormat()是必需的。这是为了确保上下文之间的资源共享保持功能,因为所有内部上下文都是使用正确的版本和概要文件创建的。

绘画技巧

如上所述,子类QOpenGLWidget以以下方式呈现纯3D内容:

重新实现initializeGL()和resizeGL()函数,以设置OpenGL状态并提供透视转换。

重新实现paintGL()以绘制3D场景,仅调用OpenGL函数。

还可以使用QPaint在QOpenGLWidget子类上绘制2D图形:

在paintGL()中,不要发出OpenGL命令,而是构造一个QPainter对象以在小部件上使用。

使用QPaint的成员函数绘制基本体。仍然可以发出直接的OpenGL命令。但是,你必须确保调用画家的BeginativePainting()和endNativePainting()来包含这些内容。

当仅使用QPaint执行绘制时,也可以像对普通小部件一样执行绘制:通过重新实现paintEvent()。

重新实现paintEvent()函数。构造一个针对小部件的QPaint对象。将小部件传递给构造函数或QPaint::begin()函数。

使用QPaint的成员函数绘制基本体。绘制完成后,QPaint实例将被销毁。或者,显式调用QPaint::end()。

三、例子代码

3.1 头文件: 重载QOpenGLWidget

#ifndef MYGLWIDGET_H #define MYGLWIDGET_H #include #include #include #include #include #include #include #include #include class MyGLWidget : public QOpenGLWidget, protected QOpenGLFunctions { Q_OBJECT public: explicit MyGLWidget(QWidget *parent = 0); signals: public slots: void initializeGL() Q_DECL_OVERRIDE; void resizeGL(int w, int h) Q_DECL_OVERRIDE; void paintGL() Q_DECL_OVERRIDE; void setImage(const QImage &image); void initTextures(); void initShaders(); private: QVector vertices; QVector texCoords; QOpenGLShaderProgram program; QOpenGLTexture *texture; QMatrix4x4 projection; }; #endif // MYGLWIDGET_H

3.2 源文件:QOpenGLWidget

#include "myglwidget.h" #include #include MyGLWidget::MyGLWidget(QWidget *parent) : QOpenGLWidget(parent) { } void MyGLWidget::initTextures() { // 加载 Avengers.jpg 图片 texture = new QOpenGLTexture(QOpenGLTexture::Target2D); texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); texture->setMagnificationFilter(QOpenGLTexture::Linear); //重复使用纹理坐标 //纹理坐标(1.1, 1.2)与(0.1, 0.2)相同 texture->setWrapMode(QOpenGLTexture::Repeat); //设置纹理大小 texture->setSize(this->width(), this->height()); //分配储存空间 texture->allocateStorage(); } void MyGLWidget::initShaders() { //纹理坐标 texCoords.append(QVector2D(0, 1)); //左上 texCoords.append(QVector2D(1, 1)); //右上 texCoords.append(QVector2D(0, 0)); //左下 texCoords.append(QVector2D(1, 0)); //右下 //顶点坐标 vertices.append(QVector3D(-1, -1, 1));//左下 vertices.append(QVector3D(1, -1, 1)); //右下 vertices.append(QVector3D(-1, 1, 1)); //左上 vertices.append(QVector3D(1, 1, 1)); //右上 QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this); const char *vsrc = "attribute vec4 vertex;\n" "attribute vec2 texCoord;\n" "varying vec2 texc;\n" "void main(void)\n" "{\n" " gl_Position = vertex;\n" " texc = texCoord;\n" "}\n"; vshader->compileSourceCode(vsrc);//编译顶点着色器代码 QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this); const char *fsrc = "uniform sampler2D texture;\n" "varying vec2 texc;\n" "void main(void)\n" "{\n" " gl_FragColor = texture2D(texture,texc);\n" "}\n"; fshader->compileSourceCode(fsrc); //编译纹理着色器代码 program.addShader(vshader);//添加顶点着色器 program.addShader(fshader);//添加纹理碎片着色器 program.bindAttributeLocation("vertex", 0);//绑定顶点属性位置 program.bindAttributeLocation("texCoord", 1);//绑定纹理属性位置 // 链接着色器管道 if (!program.link()) close(); // 绑定着色器管道 if (!program.bind()) close(); } void MyGLWidget::initializeGL() { initializeOpenGLFunctions(); //初始化OPenGL功能函数 glClearColor(0, 0, 0, 0); //设置背景为黑色 glEnable(GL_TEXTURE_2D); //设置纹理2D功能可用 initTextures(); //初始化纹理设置 initShaders(); //初始化shaders } void MyGLWidget::resizeGL(int w, int h) { // 计算窗口横纵比 qreal aspect = qreal(w) / qreal(h ? h : 1); // 设置近平面值 3.0, 远平面值 7.0, 视场45度 const qreal zNear = 3.0, zFar = 7.0, fov = 45.0; // 重设投影 projection.setToIdentity(); // 设置透视投影 projection.perspective(fov, static_cast(aspect), zNear, zFar); } void MyGLWidget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除屏幕缓存和深度缓冲 QMatrix4x4 matrix; matrix.translate(0.0, 0.0, -5.0); //矩阵变换 program.enableAttributeArray(0); program.enableAttributeArray(1); program.setAttributeArray(0, vertices.constData()); program.setAttributeArray(1, texCoords.constData()); program.setUniformValue("texture", 0); //将当前上下文中位置的统一变量设置为value texture->bind(); //绑定纹理 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);//绘制纹理 texture->release(); //释放绑定的纹理 texture->destroy(); //消耗底层的纹理对象 texture->create(); } void MyGLWidget::setImage(const QImage &image) { texture->setData(image); //设置纹理图像 //设置纹理细节 texture->setLevelofDetailBias(-1);//值越小,图像越清晰 update(); }

3.3 主函数: 调用测试

UI界面拖一个Qwidget控件,提升为MyGLwidget类(继承QopenGLWidget重写的类)

#include "widget.h" #include "ui_widget.h" #include "myglwidget.h" #include Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); //this->setWindowFlags(Qt::FramelessWindowHint); //this->setWindowOpacity(0.5); connect(&timer, &QTimer::timeout, this, &Widget::slotUpdate); timer.start(40); } Widget::~Widget() { delete ui; } void Widget::slotUpdate() { ui->widget->setImage(QImage(":/image/1161.24.png")); }

GPU加速云服务器 渲染

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Laravel 7发行说明
下一篇:关于小熊派抄袭我司开源项目代码行为的谴责声明
相关文章