我正在编写一个小程序来模拟动画。我使用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();
}
答案 0 :(得分:0)
Qt的QGLWidget期望您从其重载的paintGL
函数执行所有绘图操作,以便它可以很好地与Qt的双缓冲区管理进行迭代。
另外,为什么你绕过FBO更新纹理呢?这是非常低效的并且引入了许多同步点。使用 Pixel 缓冲区对象并使用glTexSubImage2D更新纹理。
答案 1 :(得分: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,我不太确定,我需要检查它。
非常感谢你。