您当前的位置: 首页 >  qt

龚建波

暂无认证

  • 3浏览

    0关注

    313博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

OpenGL with QtWidgets:练习之绘制2D波浪进度球

龚建波 发布时间:2021-05-05 20:01:17 ,浏览量:3

接上次的环形进度条练习:环形进度条

1.实现思路

在上次环形进度条的基础上稍加改进,通过调节着色器颜色绘制的波浪进度球。

文本绘制:使用 Qt 自带的 QPainter 绘制,由于是平面图,没有自己做纹理或者字体。

抗锯齿:还是使用的 smoothstep 算过渡值,这也导致 shader 代码有点臃肿。

圆形绘制:根据坐标到中心距离来填充不同的颜色,波浪也是根据幅度来填充不同的颜色,后面打算用几何着色器改一改。

存在的两个问题:

1.1.这里面有个比较麻烦的就是多个色块之间的抗锯齿,目前还没完美解决。因为我只有一个片元着色器程序,绘制也是一次完成的,没法先画到一个图上,别的图层再叠加上去。

1.2.目前很多属性没有导出,比如波浪幅度,周期长度,移动速度等等,也没有可配置的颜色表。

2.实现代码

(项目 git 链接:https://github.com/gongjianbo/EasyOpenGL2D)

实现效果(GIF):

主要实现代码:

#ifndef WAVEPROGRESSBAR_H
#define WAVEPROGRESSBAR_H

#include 
#include 
#include 
#include 
#include 

#include 
#include 

//龚建波:进度球
class WaveProgressBar : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
    Q_PROPERTY(double drawValue READ getDrawValue WRITE setDrawValue)
public:
    explicit WaveProgressBar(QWidget *parent = nullptr);
    ~WaveProgressBar();

    void setRange(double min,double max);
    void setValue(double value);

    double getDrawValue() const;
    void setDrawValue(double value);

protected:
    //设置OpenGL资源和状态。在第一次调用resizeGL或paintGL之前被调用一次
    void initializeGL() override;
    //渲染OpenGL场景,每当需要更新小部件时使用
    void paintGL() override;
    //设置OpenGL视口、投影等,每当尺寸大小改变时调用
    void resizeGL(int width, int height) override;

private:
    //着色器程序
    QOpenGLShaderProgram shaderProgram;
    //顶点数组对象
    QOpenGLVertexArrayObject vao;
    //顶点缓冲
    QOpenGLBuffer vbo;
    //属性动画
    QPropertyAnimation *animation;
    //进度值
    double progressMin=0;
    double progressMax=100;
    double progressValue=0; //设置的值
    double progressDraw=0; //绘制临时值
    //定时动画
    QTimer *timer;
    int timeValue=0;
};
#endif // WAVEPROGRESSBAR_H
#include "WaveProgressBar.h"

#include 
#include 

WaveProgressBar::WaveProgressBar(QWidget *parent)
    : QOpenGLWidget(parent)
{
    animation=new QPropertyAnimation(this,"drawValue");
    animation->setDuration(2000); //动画持续时间
    animation->setEasingCurve(QEasingCurve::OutQuart); //先快后慢

    timer=new QTimer(this);
    connect(timer,&QTimer::timeout,this,[this]{
        if(isHidden())
            return;
        //暂时没有考虑周期
        timeValue+=2;
        if(timeValue>=360)
            timeValue=0;
        update();
    });
    timer->start(30);
}

WaveProgressBar::~WaveProgressBar()
{
    makeCurrent();
    vbo.destroy();
    vao.destroy();
    doneCurrent();
}

void WaveProgressBar::setRange(double min, double max)
{
    if(progressMaxsetStartValue(progressDraw);
    animation->setEndValue(progressValue);
    animation->start();
}

double WaveProgressBar::getDrawValue() const
{
    return progressDraw;
}

void WaveProgressBar::setDrawValue(double value)
{
    progressDraw=value;
    update();
}

void WaveProgressBar::initializeGL()
{
    //为当前上下文初始化OpenGL函数解析
    initializeOpenGLFunctions();

    //着色器代码
    //in输入,out输出,uniform从cpu向gpu发送
    //[aPos]两个三角的顶点数据
    //[thePos]表示当前像素点
    const char *vertex_str=R"(#version 330 core
                           layout (location = 0) in vec2 aPos;
                           out vec2 thePos;
                           void main()
                           {
                             gl_Position = vec4(aPos, 0.0, 1.0);
                             thePos = aPos;
                           })";
    //GLSL的atan2也叫atan,不过参数不同,我们封装一个0-360度的归一化值[0,1]的版本
    //[FragColor]该点输出颜色,gl_FragColor在3移除了,自己声明一个
    //[aValue]进度值
    //[aTime]时间偏移
    //[aSmoothWidth]平滑过渡宽度
    const char *fragment_str=R"(#version 330 core
                             #define PI 3.14159265
                             uniform float aValue;
                             uniform float aTime;
                             uniform float aSmoothWidth;
                             in vec2 thePos;
                             out vec4 FragColor;

                             float myatan2(float y,float x)
                             {
                               float ret_val = 0.0;
                               if(x != 0.0){
                                 ret_val = atan(y,x);
                                 if(ret_val < 0.0){
                                   ret_val += 2.0*PI;
                                 }
                               }else{
                                 ret_val = y>0 ? PI*0.5 : PI*1.5;
                               }
                               return ret_val/(2.0*PI);
                             }

                             void main()
                             {
                             float len = abs(sqrt(pow(thePos.x,2.0)+pow(thePos.y,2.0)));
                             float alpha = smoothstep(0.6+aSmoothWidth,0.6,len);

                             FragColor = vec4(aValue,0.2,1.0,alpha);
                             if(alpha0.5) angle_diff=1.0-angle_diff;
                               float g_smooth = smoothstep(0,aSmoothWidth/2.0,abs(angle_diff-0.25));
                               if(angle_diff0&&ySmooth20) FragColor.g += 0.2*ySmooth2;
                               }else if(ySmooth2>0){
                                 FragColor.g += 0.6*ySmooth2;
                               }
                             }
                             })";


    //将source编译为指定类型的着色器,并添加到此着色器程序
    if(!shaderProgram.addCacheableShaderFromSourceCode(
                QOpenGLShader::Vertex,vertex_str)){
        qDebug()            
关注
打赏
1655829268
查看更多评论
0.0756s