Qt OpenGL更新速度极慢

时间:2013-02-12 00:13:11

标签: c++ qt opengl animation qt5

我似乎无法让Qt5以有意义的速度更新我的场景。我的场景是一个512x512纹理矩形。我得到的速度大约是每秒1帧(!)。

在我的构造函数中

   aTimer.setSingleShot(false);
   aTimer->setTimerType(Qt::PreciseTimer);
   connect(&aTimer,SIGNAL(timeout()),this,SLOT(animate()));
   aTimer.start(50);
   setAutoFillBackground(false);

void GLWidget::animate()
{
//Logic for every time step
updateGL();
}

有没有办法设定优先权?我做的事情完全是错的吗?在Qt中是否存在某种内在的更新限制,它肯定不是1 FPS的量级?我的理论是,Qt忽略了我实际更新屏幕的要求。

我试过了

  1. 插入QCoreApplication::processEvents(); ,但这没有帮助
  2. 在父窗口小部件上调用更新,并从父
  3. 运行计时器
  4. 创建一个名为animate()的函数,该函数运行forever{}并从其中调用update
  5. wigglywidget示例似乎有效,这暗示我QT OpenGL以某种方式折叠帧,忽略了我的更新调用。是否存在控制此问题的启发式方法?
  6. 重新创建的最小代码

    (版本有点不同,在wigglywidget类之后建模,但有完全相同的问题)

    git clone https://bitbucket.org/FunFarm/qtcapturesoftware.git
    

    glwidget.h

    /****************************************************************************/
    
    #ifndef GLWIDGET_H
    #define GLWIDGET_H
    
    #include <QGLWidget>
    #include <QtOpenGL/qglshaderprogram.h>
    #include <QTimer>
    #include <math.h>
    #include "time.h"
    #include <assert.h>
    #include <random>
    
    class GLWidget : public QGLWidget
    {
        Q_OBJECT
    
    public:
        GLWidget(QWidget *parent = 0);
        ~GLWidget();
        void addNoise();
    protected:
        void initializeGL();
        void paintGL();
        void timerEvent(QTimerEvent *event);
        void resizeGL(int width, int height);
    private:
        QBasicTimer timer;
        QPoint lastPos;
        GLuint textures[6];
        QVector<QVector2D> vertices;
        QVector<QVector2D> texCoords;
        QGLShaderProgram program1;
        int vertexAttr1;
        int vertexTexr1;
        //
        int heightGL;
        int widthGL;
        //
        GLubyte* noise;
        //
        QTimer* aTimer;
        //
    };
    #endif
    

    glwidget.cpp

    #include <QtWidgets>
    #include <QtOpenGL>
    #include "glwidget.h"
    
    
    #ifndef GL_MULTISAMPLE
    #define GL_MULTISAMPLE  0x809D
    #endif
    
    GLWidget::GLWidget(QWidget *parent)
        : QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
    {
        setAutoFillBackground(false);
        aTimer = new QTimer();
        timer.start(30, this); // 30 fps?
    }
    void GLWidget::timerEvent(QTimerEvent *event)
    {
        addNoise();
        update();// Doesn't matter which update function I call, this is the one from the wigglywidget example
    }
     GLWidget::~GLWidget(){}
    void GLWidget::initializeGL()
    {
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
        glShadeModel(GL_SMOOTH);
        glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);
        glEnable(GL_MULTISAMPLE);
        static GLfloat lightPosition[4] = { 0.5, 5.0, 7.0, 1.0 };
        glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
        QGLShader *vshader1 = new QGLShader(QGLShader::Vertex, this);
        const char *vsrc1 =
                "attribute vec2 coord2d;   \n"
                "attribute mediump vec4 texCoord;\n"
                "varying mediump vec4 texc;\n"
                "void main()                  \n"
                "{                            \n"
                "   gl_Position = vec4(coord2d, 0.0, 1.0); \n"
                "   texc = texCoord;\n"
                "}                          \n";
        vshader1->compileSourceCode(vsrc1);
    
        QGLShader *fshader1 = new QGLShader(QGLShader::Fragment, this);
        const char *fsrc1 =
                "uniform sampler2D texture;\n"
                "varying mediump vec4 texc;\n"
                "void main(void)\n"
                "{\n"
                "    gl_FragColor = texture2D(texture, texc.st);\n"
                "}\n"                                                  ;
        fshader1->compileSourceCode(fsrc1);
    
        program1.addShader(vshader1);
        program1.addShader(fshader1);
        program1.link();
        vertexAttr1 = program1.attributeLocation( "coord2d");
        vertexTexr1 = program1.attributeLocation( "texCoord");
    
        // Create the vertex buffer.
        vertices.clear();
        float u=1;
    #define AVEC -u,u
    #define BVEC -u,-u
    #define CVEC u,u
    #define DVEC u,-u
        vertices << QVector2D(AVEC);
        vertices << QVector2D(BVEC);
        vertices << QVector2D(CVEC);
        vertices << QVector2D(BVEC);
        vertices << QVector2D(DVEC);
        vertices << QVector2D(CVEC);
        // Create the texture vertex buffer
    #define TAVEC 0,1
    #define TBVEC 0,0
    #define TCVEC 1,1
    #define TDVEC 1,0
        texCoords << QVector2D(TAVEC);
        texCoords << QVector2D(TBVEC);
        texCoords << QVector2D(TCVEC);
        texCoords << QVector2D(TBVEC);
        texCoords << QVector2D(TDVEC);
        texCoords << QVector2D(TCVEC);
        QPixmap aMap(":/images/testmap.jpg");
        assert(aMap.width());
        heightGL = aMap.height();
        widthGL = aMap.width();
        textures[0] =bindTexture(aMap,GL_TEXTURE_2D,GL_LUMINANCE);
        noise = (GLubyte*) calloc(1*widthGL*heightGL,sizeof(GLubyte));//GL_RGB8
        memset(noise,100,1*widthGL*heightGL);
        //
    }
    void GLWidget::addNoise()
    {
        std::default_random_engine e((unsigned int)(time(0)));
        GLubyte c = e()%256;
        assert(noise);
        for (int i = 0; i<heightGL;i++)
        {
            for(int j =0;j<widthGL;j++)
                noise[i*widthGL+j]= c;
        }
    }
    
    void GLWidget::paintGL()
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
        //
        //
    
        program1.bind();
        program1.setUniformValue("texture", 0);
        program1.enableAttributeArray(vertexAttr1);
        program1.enableAttributeArray(vertexTexr1);
        program1.setAttributeArray(vertexAttr1, vertices.constData());
        program1.setAttributeArray(vertexTexr1, texCoords.constData());
        glBindTexture(GL_TEXTURE_2D, textures[0]);
        glTexSubImage2D(GL_TEXTURE_2D,0,0,0,
                        widthGL,heightGL,GL_LUMINANCE,GL_UNSIGNED_BYTE, //lets hope these are correct
                        noise);
        glDrawArrays(GL_TRIANGLES, 0, vertices.size());
        program1.disableAttributeArray(vertexTexr1);
        program1.disableAttributeArray(vertexAttr1);
        program1.release();
    }
    
    void GLWidget::resizeGL(int width, int height)
    {
        int side = qMin(width, height);
        glViewport((width - side) / 2, (height - side) / 2, side, side);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);
        glMatrixMode(GL_MODELVIEW);
    
    }
    

    的main.cpp

    /****************************************************************************/
    #include <QApplication>
    #include <QDesktopWidget>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        //cameraView cV;
        //cV.show();
        GLWidget mW;
        mW.show();
        return a.exec();
    }
    

    test.pro

    HEADERS       = glwidget.h \
        cameraview.h
    SOURCES       = glwidget.cpp \
                    main.cpp \
        cameraview.cpp
    QT           += opengl widgets
    
    CONFIG += console
    CONFIG += c++11
    
    # install
    target.path = $$[QT_INSTALL_EXAMPLES]/qt_OpenGL_3x/02_First_Triangle
    sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS 02-first-triangle.pro
    sources.path = $$[QT_INSTALL_EXAMPLES]/qt_OpenGL_3x/02_First_Triangle
    INSTALLS += target sources
    
    
    simulator: warning(This example might not fully work on Simulator platform)
    
    FORMS += \
        cameraview.ui
    
    RESOURCES += \
        images.qrc
    
    OTHER_FILES +=
    

1 个答案:

答案 0 :(得分:10)

我克隆了存储库并对代码进行了一些更改,以帮助您调试问题。首先,使用 std :: cout paintGL()的开头打印一条消息:

void GLWidget::paintGL()
{
   static int xyz = 0;
   std::cout << "PaintGL begin " << xyz << std::endl;

paintGL末尾的另一条消息。之后,递增计数器变量:

   program1.release();

   std::cout << "PaintGL end " << xyz << std::endl;
   xyz++;
}

这种方法清楚地表明,由于在2秒内打印到控制台的消息量,paintGL()每秒被调用近30次:

PaintGL begin 0
PaintGL end 0
PaintGL begin 1
PaintGL end 1
...
...
PaintGL begin 60
PaintGL end 60
PaintGL begin 61
PaintGL end 61

因此可以放弃计时器存在问题的理论。 计时器很好,你确实每秒刷一次30个计时器。

问题可能在您的代码中的其他位置。由于您只在存储库中共享了一部分应用程序,我担心我将无法再为您提供帮助。

修改

我注意到addNoise()里面有一个随机数生成器。如果您希望根据其他方法生成的数字在每{{}}}次呼叫时更改绘图,您会感到失望。

实现的当前数字生成机制对毫秒更改不敏感,因此在同一秒内对paintGL()的所有调用都将生成相同的数字,这反过来会在窗口上绘制相同的内容整个第二个。这就解释了为什么图纸每秒只改变一次。

要解决此问题,我建议您查看: