1

我正在编写一个小程序来模拟动画。我使用 QGLWidget 来显示动态图像以模仿图片动画。基本思想是使用纹理并通过QGLFamebufferOject::blitFramebuffer对其进行更新。每次,图像数组都会改变,然后帧缓冲区也会改变。

代码可以运行,图像可以向前移动,但是图像有斩波问题,或者闪烁,不流畅。

下面是一个类的代码:

GLWidget::GLWidget(QWidget *parent) : QGLWidget(QGLFormat(), parent)
{
    makeCurrent();

    if (QGLFramebufferObject::hasOpenGLFramebufferBlit()) {

        QGLFramebufferObjectFormat format;
        render_fbo = new QGLFramebufferObject(640, 480, format);
        texture_fbo = new QGLFramebufferObject(640, 480);

    } else {
        render_fbo = new QGLFramebufferObject(640, 480);
        texture_fbo = render_fbo;
    }

    tile_list = glGenLists(1);
    glNewList(tile_list, GL_COMPILE);
    glBegin(GL_QUADS);
    {
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
    }
    glEnd();
    glEndList();

    backbufferImg = new unsigned char[640 * 480 * sizeof(unsigned char) * 3];

}

GLWidget::~GLWidget()
{
}

void GLWidget::initializeGL()
{

}

void GLWidget::resizeGL(int width, int height)
{

}

void GLWidget::paintGL()
{

}

void GLWidget::saveGLState()
{
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
}

void GLWidget::restoreGLState()
{
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
    glPopAttrib();
}

void GLWidget::changeTextureImage(int nextColumn, int direction)
{
    // code about chaning backbufferImg
    // ...

    // call draw
    draw();
}


void GLWidget::draw()
{
    makeCurrent();

    QPainter p(this);  // used for text overlay

    // save the GL state set for QPainter
    saveGLState();

    QPainter fbo_painter(render_fbo);
    QImage renderImg(backbufferImg, 640, 480, QImage::Format_RGB888);

    fbo_painter.begin(render_fbo);
    QRect rect(640, 480);
    fbo_painter.drawImage(rect, renderImg, rect);
    fbo_painter.end();

    if (render_fbo != texture_fbo) {
        QGLFramebufferObject::blitFramebuffer(texture_fbo, rect, render_fbo, rect);
    } else {
      //  qDebug() << "render_fbo == texture_fbo";
    }

    // draw into the GL widget
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glViewport(0, 0, width(), height());
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glBindTexture(GL_TEXTURE_2D, texture_fbo->texture());

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glEnable(GL_TEXTURE_2D);

    glPushMatrix();
    glScalef(1.0f, 1.0f, 1.0f);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    glCallList(tile_list);
    glPopMatrix();

    // restore the GL state that QPainter expects
    restoreGLState();

    glFinish();
}
4

2 回答 2

0

Qt 的 QGLWidget 期望您从其重载执行所有绘图操作paintGL函数执行所有绘图操作,以便它与 Qt 的双缓冲区管理很好地迭代。

另外,您为什么要绕过 FBO 来更新纹理?这是非常低效的并且引入了很多同步点。使用像素缓冲区对象并使用 glTexSubImage2D 更新纹理。

于 2013-01-19T19:25:44.383 回答
0

非常感谢!我改了代码,把绘图代码放在了paintGL里面,没有使用FBO的blit方法。好多了,但仍然需要改进代码。以下是代码:

GLWidget::GLWidget(QWidget *parent) :
    QGLWidget(QGLFormat(), parent)
{
    makeCurrent();

    fbo = new QGLFramebufferObject(WIDTH, HEIGHT);

    tile_list = glGenLists(1);
    glNewList(tile_list, GL_COMPILE);
    glBegin(GL_QUADS);
    {
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);
        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);
    }
    glEnd();
    glEndList();

    backbufferImg = new unsigned char[WIDTH * HEIGHT * sizeof(unsigned char) * 3];
}

GLWidget::~GLWidget()
{
    glDeleteLists(tile_list, 1);
    delete fbo;
    delete backbufferImg;
}

void GLWidget::initializeGL()
{

}

void GLWidget::resizeGL(int width, int height)
{

}

void GLWidget::paintGL()
{
    glViewport(0, 0, fbo->size().width(), fbo->size().height());

    glMatrixMode(GL_MODELVIEW);

    // render to the framebuffer object

    fbo->bind();
    glBindTexture(GL_TEXTURE_2D, refreshTexture);
    glCallList(tile_list);
    fbo->release();

 //////////////////////////////////////////////////////////////////////

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glViewport(0, 0, width(), height());
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glBindTexture(GL_TEXTURE_2D, fbo->texture());

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glEnable(GL_TEXTURE_2D);

    glPushMatrix();
    glScalef(1.0f, 1.0f, 1.0f);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    glCallList(tile_list);
    glPopMatrix();

    // restore the GL state that QPainter expects
    restoreGLState();

    glFinish();
}



void GLWidget::saveGLState()
{
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
}

void GLWidget::restoreGLState()
{
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
    glPopAttrib();
}



void GLWidget::refreshTextureImage(int nextColumn, int direction)
{
    // upadte backbufferImg 
    // add code...

    QImage renderImg(backbufferImg, WIDTH, HEIGHT, QImage::Format_RGB888);

    refreshTexture = bindTexture(renderImg);
    updateGL();
}

我会尝试你建议的方法。但我认为帧缓冲区和像素缓冲区在同一级别。这意味着没有太大的性能差异。对于 glTexSubImage2D,我不太确定,我需要检查一下。

太感谢了。

于 2013-01-20T22:30:23.247 回答