13. OPenGL与QT界面元素交互控制图形渲染

1. 说明:

前面文章中讲到的 OPenGL 渲染都是在页面加载完成即立刻渲染的,如果向控制图形渲染的时间,可以在QT界面中添加一些元素来进行控制。此时需要用到OPenGL当中的makeCurrent(),update(),doneCurrent()函数。
效果展示:

opengl与qt交互

2. 步骤一:

在myopenglwidget.h文件中添加一个枚举,放置要绘制的图形类型,同时声明三个函数,分别为drawShape(),clearGraphic(),setWireFrame(),方便主界面上的元素调用,相应代码如下:
myopenglwidget.h:

#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H

#include 
#include 

#include 
#include 

class MyOpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    //添加图形类型枚举
    enum Shape{None,Rect,Circle,Triangle};
    
    explicit MyOpenGLWidget(QWidget *parent = nullptr);
	//添加三个辅助函数
    void drawShape(Shape shape);
    void clearGraphic();
    void setWireFrame(bool wireFrame);

protected:
    virtual void initializeGL() override;
    virtual void resizeGL(int w, int h) override;
    virtual void paintGL() override;

signals:

private:
	//定义一个中间变量
    Shape m_shape;
};
#endif // MYOPENGLWIDGET_H

3. 步骤二:

对上面的三个辅助函数进行设计,其中每触发一个函数,都应该让OPenGL重新绘制,此时应调用 update() 函数,而在更新视图之前,需要记录当前的视图是什么样的,所以还需要在此之前调用 makeCurrent() 函数,视图更新结束后,需要告知OPenGL已经绘制完毕,此时需要调用 doneCurrent() 函数,相应代码如下:
myopenglwidget.cpp:

#include "myopenglwidget.h"

unsigned int VBO,VAO;
//添加一个索引控制器
unsigned int EBO;

//定义一个全局的着色器控制器
unsigned int shaderProgram;

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

//使用4个顶点数据绘制两个三角形
float vertices2[] = {
    0.5f,0.5f,0.0f,
    0.5f,-0.5f,0.0f,
    -0.5f,-0.5f,0.0f,
    -0.5f,0.5f,0.0f
};

//添加索引数据
unsigned int indices[]={
    0,1,3,
    1,2,3
};

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

}
//绘制图形辅助函数
void MyOpenGLWidget::drawShape(MyOpenGLWidget::Shape shape)
{
    makeCurrent();//记录当前视图
    m_shape = shape;
    update();//视图更新
    doneCurrent();//结束视图更新
}
//清空函数
void MyOpenGLWidget::clearGraphic()
{
    makeCurrent();
    drawShape(MyOpenGLWidget::None);
    makeCurrent();
    glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
    update();
    doneCurrent();
}
//设置线框模式函数
void MyOpenGLWidget::setWireFrame(bool wireFrame)
{
    makeCurrent();
    if(wireFrame){
        glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);//以线框模式绘制图形
    }else{
        glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);//以填充模式绘制图形
    }
    update();
    doneCurrent();
}

void MyOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();

    shaderProgram = glCreateProgram();
    //void glGenVertexArrays(GLsizei n, GLuint *arrays)生成顶点数组对象名称
    // n: 要产生的VAO对象的数量
    // arrays: 存放产生的VAO对象的名称
    glGenVertexArrays(1,&VAO);

    // void glGenBuffers(GLsizei n,GLuint *buffers)生成顶点缓冲对象
    // n: 要产生的VBO对象的数量
    // arrays: 存放产生的VBO对象的名称
    glGenBuffers(1,&VBO);

    //初始化索引器
    glGenBuffers(1,&EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof (indices),indices,GL_STATIC_DRAW);

    //绑定VAO和VBO
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER,VBO);
    //在VBO中存入顶点数据
    glBufferData(GL_ARRAY_BUFFER,sizeof (vertices2),vertices2,GL_STATIC_DRAW);
    //告诉VAO怎么在VBO中拿数据
    glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof (float),(void*)0);
    //开启第一个VAO
    glEnableVertexAttribArray(0);
    //用完之后解除绑定(信息已经被记录下来了)
    glBindBuffer(GL_ARRAY_BUFFER,0);
    glBindVertexArray(0);
}

void MyOpenGLWidget::resizeGL(int w, int h)
{
    Q_UNUSED(w);
    Q_UNUSED(h);

}

void MyOpenGLWidget::paintGL()
{
    glClearColor(0.5f,0.9f,0.4f,1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    //在渲染前只需开启对应的VAO即可
    glBindVertexArray(VAO);
    //switch判断 m_shape 的类型,进行不同图形的绘制
    switch (m_shape) {
    case Rect:
        glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,&indices);
        break;
    default:
        break;
    }
}

4. 步骤三:

在主界面中添加三个按钮,分别用来绘制,清空,设置线框模式,并相应其clicked信号,调用对应的函数即可,相应代码如下:
myopenglwidget.h:

#ifndef LEARNOPENGL_H
#define LEARNOPENGL_H

#include 

QT_BEGIN_NAMESPACE
namespace Ui { class LearnOpenGL; }
QT_END_NAMESPACE

class LearnOpenGL : public QMainWindow
{
    Q_OBJECT

public:
    LearnOpenGL(QMainWindow *parent = nullptr);
    ~LearnOpenGL();

private slots:
	//三个按钮的槽函数
    void on_btn_drawRect_clicked();

    void on_btn_Clear_clicked();

    void on_btn_setFrame_clicked();

private:
    Ui::LearnOpenGL *ui;
};
#endif // LEARNOPENGL_H

myopenglwidget.cpp:

#include "learnopengl.h"
#include "ui_learnopengl.h"

LearnOpenGL::LearnOpenGL(QMainWindow *parent)
    : QMainWindow(parent)
    , ui(new Ui::LearnOpenGL)
{
    ui->setupUi(this);
    setCentralWidget(ui->openGLWidget);

}

LearnOpenGL::~LearnOpenGL()
{
    delete ui;
}

void LearnOpenGL::on_btn_drawRect_clicked()
{
    ui->openGLWidget->drawShape(MyOpenGLWidget::Rect);//调用绘制图形
}

void LearnOpenGL::on_btn_Clear_clicked()
{
    ui->openGLWidget->clearGraphic();//调用清空图形
}

bool frame = true;
void LearnOpenGL::on_btn_setFrame_clicked()
{
    ui->openGLWidget->setWireFrame(frame);//调用线框模式
    frame = !frame;
}

你可能感兴趣的:(qt,交互,图形渲染)