QOpenglWidget 画动态矩形

    使用的都是opengl的函数,只不过Qt再封装了一遍;在使用过程中有一些注意点,需要记下。

我的头文件申明如下

#ifndef GLDRAWWIDGET_H
#define GLDRAWWIDGET_H

#include 
#include 
#include 
QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
class GlDrawWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT
public:
    GlDrawWidget(QWidget *parent = 0);
    ~GlDrawWidget();
    virtual void drawRect(QRect &r); //相对于本窗体的Rect

protected:
    void initializeGL() override;
    void paintGL() override;

private:
    QOpenGLShaderProgram *shaderProgram = nullptr;
    QOpenGLBuffer vbo;
};

#endif // GLDRAWWIDGET_H

这是我仔细研究Qt中封装之后的最简洁版本,Qt对opengl的介绍太少了,就只有几个demo。

#include "gldrawwidget.h"
#include 
#include 

GlDrawWidget::GlDrawWidget(QWidget *parent)
    : QOpenGLWidget(parent)
{
}

GlDrawWidget::~GlDrawWidget()
{
    makeCurrent();vbo.destroy();
}

void GlDrawWidget::initializeGL()
{
    initializeOpenGLFunctions();
    GLfloat cols[12]{  //我预先指定了边框的颜色,这里我使用的是QOpenglBuffer,且是一个私有变量,在对象存在期间不会销毁,所以不用加static关键字,加上也可以。如果是直接setAttributeArray()一个局部的数据就要加上static,因为画一个顶点都会访问一次该buffer中的颜色,如果该内存不在了,结果会不对,貌似opengl内部没有把这个数据存到它自己那里(个人根据结果猜测)。但是如果是在paintGL()函数中临时加载数据就可以是栈区的,因为paintGL()函数中会执行画的操作,没画完之前,栈区的数据是不会释放的。

        0.0f,1.0f,1.0f, 0.0f,1.0f,1.0f,
        0.0f,1.0f,1.0f, 0.0f,1.0f,1.0f,
    };
    vbo.create(); //创建buffer
    vbo.bind();   //绑定到当前上下文
    vbo.allocate(32 * sizeof(GLfloat)); //分配32个GLfloat的数据空间,其中前24个点对应四个边线顶点的颜色
    vbo.write(0,cols,sizeof(cols)); //在起始位置写入颜色

    shaderProgram = new QOpenGLShaderProgram(this);

    static const char vsrc[]{ //很简单就是传入顶点,和颜色
        "attribute highp vec4 vertex;\n" \
        "attribute mediump vec4 col;\n" \
        "varying mediump vec4 color;\n" \
        "void main()\n"
        "{\n"
        "   gl_Position=vertex;\n"
        "   color=col;\n"
        "}"
    };
    QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex,this);
    vshader->compileSourceCode(vsrc);

    static const char fsrc[]{
        "varying mediump vec4 color;\n"
        "void main()\n"
        "{\n"
        "   gl_FragColor=color;\n"
        "}"
    };
    QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment,this);
    fshader->compileSourceCode(fsrc);

    shaderProgram->addShader(vshader);
    shaderProgram->addShader(fshader);
    shaderProgram->bind();
    shaderProgram->link(); //必须在link、和bind之后,才能设置attribute变量的值,opegnl决定的
    shaderProgram->enableAttributeArray("vertex");
    shaderProgram->enableAttributeArray("col");
    shaderProgram->setAttributeBuffer("vertex",GL_FLOAT,24 * sizeof(GLfloat),2,2*sizeof(GLfloat));
    shaderProgram->setAttributeBuffer("col",GL_FLOAT,0,3,3*sizeof(GLfloat));
    glEnable(GL_DEPTH_TEST); //启动深度测试
//    glEnable(GL_LINE_SMOOTH);
    glClearColor(0.0f,0.0f,0.0f,0.0f); //背景透明,还需设置FramelessWindowHint和WA_TranslucentBackground
}

void GlDrawWidget::paintGL()
{
    glDrawArrays(GL_LINE_LOOP,0,4); //根据点顺序画封闭线
}

void GlDrawWidget::drawRect(QRect &r)
{
    makeCurrent();  //必须使用该函数;使其处理渲染当前opengl上下文的状态,并且会绑定内存空间到那个opengl上下文;后面对opengl中的操作才会有效。在initialIzeGL()和paintGL()中系统会在调用它们之前调用这个接口,所以不用再调。也可以把操作直接写到paintGL()中。
    GLfloat w = 2 * GLfloat(r.width()) / width();
    GLfloat h = 2 * GLfloat(r.height()) / height();
    GLfloat x = -1.0 + 2 * GLfloat(r.x()) / width();
    GLfloat y = -1.0 + 2 * GLfloat(r.y()) / height();
    GLfloat vertexs[]{
        x,y,
        x + w, y,
        x + w, y + h,
        x, y + h
    }; //变换顶点到opengl坐标
    vbo.write(24 * sizeof(GLfloat),vertexs,sizeof(vertexs)); //写入数据
    update(); //重新绘画
}

    以下是我在主函数中做的一个测试。

#include "gldrawwidget.h"
#include 
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    GlDrawWidget w;
//    w.setWindowFlag(Qt::FramelessWindowHint);
//    w.setAttribute(Qt::WA_TranslucentBackground);
    QPushButton ptn(&w);
    QObject::connect(&ptn,&QPushButton::clicked,[&]{
        static double rate = 1.0;
        w.drawRect(w.rect().adjusted(rate,rate,-rate,-rate));
        rate += 4;
    });
    w.show();

    return a.exec();
}
QOpenglWidget 画动态矩形_第1张图片

你可能感兴趣的:(Qt,opengl)