2.通过QOpenGLWidget绘制三角形

  • Post author:
  • Post category:其他


上章传送门参考:



1.opengl绘制三角形


1.QOpenGLWidget的早先版本

QGLWidget是遗留Qt OpenGL模块的一部分,和其他QGL类一样,应该在新的应用程序中避免使用。相反,从Qt 5.4开始,最好使用QOpenGLWidget和QOpenGL类。

如果开发XP平台,由于兼容性问题,Qt5.4(不含)之后的QtOpenglWidget 则不兼容,建议还是用QGLWidget.


2.QOpenGLWidget类是用于呈现OpenGL图形的部件

QOpenGLWidget提供显示集成到Qt应用程序中的OpenGL图形的功能。使用起来非常简单:让类继承它,并像其他QWidget一样使用子类,额外可以选择使用QPainer和标准的OpenGL渲染命令。

QOpenGLWidget提供了三个方便的虚拟函数,子类中重新实现这些函数来执行OpenGL绘制任务:

  • paintGL():渲染OpenGL场景。该函数里面主要绘制部件,比如在全屏视频上面显示滑动条
  • resizeGL ():当窗口尺寸发生变化时被调用,然后会调用paintGL()函数重新绘制一次(并且第一次显示时也会调用resizeGL() )。
  • initializeGL():用于初始化,设置OpenGL要呈现的画面,只在程序开始时运行一次,之后不会再运行。

其中在initializeGL()中初始化具体如下所示:

然后在paintGL()中,每次当我们要绘制不同的物体时,便调用bind()来绑定对象、绘制完后,解绑对象,如果还要绘制下个物体,那么就取出对应的VAO,绑定它,绘制完物体后,再解绑。

3.本章需要用到的名词和类介绍



  • Program:


    用来编译顶点和片元着色器的程序,简称着色器程序


  • VBO:


    顶点缓冲对象(顶点输入,顶点位置),通过VBO将大量顶点存储在GPU内存(通常被称为显存)中.必须在初始化VAO之前初始化好.等VAO.bind后就可以释放了.


  • VAO:


    顶点数组对象,用于存储顶点状态配置信息,每当刷新时,通过VAO进行绘制(告诉着色器如何解释内存中的顶点数据).


  • QOpenGLBuffer:


    用来创建vbo对象或者ebo对象(索引缓冲对象)


  • QOpenGLVertexArrayObject:


    用来创建vao对象,用于存储顶点状态配置信息,每当界面刷新时,则通过VAO进行绘制


  • QOpenGLShaderProgram:


    着色器程序,用来链接顶点shader和片元shader,一旦编译链接成功,就可以通过调用bind()成员函数进行激活.


4.三角形示例


5.头文件代码

#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QObject>
#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLTexture>
#include <QDebug>


class Glwidget : public QOpenGLWidget , protected QOpenGLFunctions
{
    Q_OBJECT
public:
    explicit Glwidget(QWidget *parent = nullptr);

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

signals:


private:
    QOpenGLShaderProgram *program;
    QOpenGLVertexArrayObject vao;
    QOpenGLBuffer  vbo;
};

#endif // GLWIDGET_H


6.源文件代码

#include "glwidget.h"


GLSL3.0版本后,废弃了attribute关键字(以及varying关键字),属性变量统一用in/out作为前置关键字
#define GLVERSION  "#version 330 core\n"
#define GET_GLSTR(x) GLVERSION#x


const char *vertexShaderSource = GET_GLSTR(
    layout (location = 0) in vec3 aPos;
    void main()
    {
        gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
    }
);


const char *fragmentShaderSource = GET_GLSTR(
    out vec4 FragColor;

    void main()
    {
        FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
    }
);


Glwidget::Glwidget(QWidget *parent) : QOpenGLWidget(parent)
{

}



void Glwidget::paintGL()
{

    glClear(GL_COLOR_BUFFER_BIT);

    program->bind();
    vao.bind();
    glDrawArrays(GL_TRIANGLES, 0, 3);   //绘制3个定点,样式为三角形

    vao.release();       //解绑
    program->release();  //解绑
}

void Glwidget::initializeGL()
{
    bool ret;
    initializeOpenGLFunctions();

    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);    //设置背景色为白色

    float vertices[] = {
        -0.5f, -0.5f, 0.0f,
         0.5f, -0.5f, 0.0f,
         0.0f,  0.5f, 0.0f
    };


    // 初始化VBO(顶点输入,顶点位置)
    vbo.create();
    vbo.bind();              //绑定到当前的OpenGL上下文,
    vbo.allocate(vertices, sizeof(vertices));
    vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);

    // 初始化顶点着色器和片元着色器,链接到着色器程序对象(Shader Program Object)
    program = new  QOpenGLShaderProgram(this);
    program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
    program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
    ret = program->link();
    if(!ret) {
        qDebug()<<"QOpenGLShaderProgram ERR:"<<program->log();
        return;
    }
    program->bind();    // 相当于调用glUseProgram()

    // 将当前的顶点属性的配置信息(与program绑定一起)绑定到VAO(当我们打算绘制物体的时候就拿出相应的VAO,绑定它,绘制完物体后,再解绑VAO。)
    vao.create();
    vao.bind();

    // 设置顶点属性,告诉着色器如何解释内存中的顶点数据(组件数量,数据类型,顶点个数),比如xyz坐标数据类型是GL_BYTE型,还是GL_SHORT型,还是GL_FLOAT型等
    program->setAttributeBuffer(0, GL_FLOAT, 0, 3, 0);
            //location:指定要设置的顶点位置(Location)的索引值
            //type:指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT
            //offset:第一个数据的偏移量,如果是紧贴的,则填入0
            //tupleSize:每个顶点属性的组件数量。必须为1、2、3、4之一。(如我们这里aPos顶点是由3个(x,y,z)组成,而颜色是4个(r,g,b,a))
            //stride :步长,下个数据距离当前数据的之间距离,如果是紧贴的,则填0

    //解绑所有对象
    vao.release();
    vbo.release();
    program->release();
}

// 窗口尺寸变化
void Glwidget::resizeGL(int width, int height)
{
    qDebug() << "resizeGL "<<width<<":"<<height;
}

下章学习:

3.QOpenGLWidget-通过着色器来渲染渐变三角形_诺谦的博客-CSDN博客



版权声明:本文为qq_37997682原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。