我正在尝试在 Qt5.3 中做一些离屏渲染工作,我想用它QOpenGLFramebufferObject::toImage
来输出每张图片(我想在 render() 绘制不同的东西时输出几张图片)。
按照this的说明,我成功地在屏幕外渲染了我的第一张图片并输出了它。所以到未来,我写了一个例子作为下面的代码,这里是谷歌的一个包。我可以获得第一个 fbo 内容(及其正确的输出文件,但从第二次开始,fbo 没有重新渲染()并且它总是输出相同的图片)。所以我想知道在完成一次屏幕外渲染后我应该怎么做以确保下一次在qt中是正确的?或者有没有人可以告诉我如何正确设置动画QOffscreenSurface
?
qtestofffscreen.h:
#ifndef QTESTOFFSCREEN_H
#define QTESTOFFSCREEN_H
#include <QOffscreenSurface>
#include <QWindow>
#include <QtGui/QOpenGLFunctions_3_3_Core>
#include <QImage>
#include <QGLFramebufferObject>
#include <QOpenGLPaintDevice>
#include <QOpenGLFunctions>
#include <QMutex>
#include <QMutexLocker>
class QTestOffScreen : public QOffscreenSurface,
protected QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
explicit QTestOffScreen(
QScreen* targetScreen = nullptr,
const QSize& size = QSize (1, 1));
~QTestOffScreen();
virtual void render();
virtual void initialize();
void renderNow();
void setAnimating(bool animating);
bool event(QEvent *) override;
void renderLater();
int counts;
private:
QGLFramebufferObject *fbo;
bool m_animating;
bool m_update_pending;
QOpenGLContext *m_context;
QOpenGLPaintDevice *m_device;
QSize m_size;
QMutex mutex;
signals:
void doneImg(int index);
};
#endif // QTESTOFFSCREEN_H
qtestofffscreen.cpp:
#include "qtestoffscreen.h"
#include <QTime>
#include <QDebug>
#include <QCoreApplication>
#include <QOpenGLFramebufferObject>
QTestOffScreen::QTestOffScreen(QScreen *targetScreen,
const QSize &size):
QOffscreenSurface(targetScreen),
m_size(size),
fbo(Q_NULLPTR),
m_context(Q_NULLPTR),
m_device(Q_NULLPTR),
counts(100)
{
requestedFormat().setVersion(3,3);
setFormat(requestedFormat());
create();
m_context = new QOpenGLContext(this);
m_context->setFormat(format());
if (m_context->create())
{
m_context->makeCurrent(this);
m_context->functions()->initializeOpenGLFunctions();
}else
{
delete m_context;
m_context = Q_NULLPTR;
throw ("Still wrong here");
}
//To make sure m_context was initialized
//in first time entering renderNow()
delete m_context;
m_context = Q_NULLPTR;
}
QTestOffScreen::~QTestOffScreen()
{
delete m_context;
delete m_device;
if (fbo)
delete fbo;
}
void QTestOffScreen::render()
{
glClearColor(0.0f,0.0f,0.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
| GL_TEXTURE_BIT);
glViewport(0,0,1920,1080);
glOrtho(0,1920,0,1080,0,1);
glColor3f(1.0,0.0,0.0);
float tmp = float(qrand()%1000);
float count = (float)counts * 10.0f;
glLineWidth(3.0f);
glBegin(GL_LINE_LOOP);
glVertex2f(count ,count );
glVertex2f(count + 100,count);
glVertex2f(count + 50,count + 100);
glEnd();
qDebug()<<QString("current tmp is %1").arg(count);
}
void QTestOffScreen::initialize()
{
if (!fbo)
{
fbo = new QGLFramebufferObject(1920,1080,GL_TEXTURE_2D);
}
fbo->bind();
}
void QTestOffScreen::renderNow()
{
bool needsInitialize = false;
if (!m_context)
{
m_context = new QOpenGLContext(this);
m_context->setFormat(requestedFormat());
m_context->create();
if (m_context->isValid())
{
qDebug()<<"Right Here when creating m_context in renderNow";
}
needsInitialize = true;
}
if ( !m_context->makeCurrent(this) )
{
qDebug()<<"This fails in makeCurrent";
}
if (needsInitialize)
{
initializeOpenGLFunctions();
initialize();
}
render();
qDebug()<<counts;
counts--;
fbo->toImage().save(QString::number(counts) + QString(".png"));
m_context->doneCurrent();
if (counts >= 0)
{
m_update_pending = false;
emit doneImg(counts);
}
}
void QTestOffScreen::setAnimating(bool animating)
{
m_animating = animating;
m_update_pending = false;
if (m_animating)
renderLater();
}
bool QTestOffScreen::event(QEvent *event)
{
switch (event->type())
{
case QEvent::UpdateRequest:
m_update_pending = true;
renderNow();
return true;
default:
return QOffscreenSurface::event(event);
}
}
void QTestOffScreen::renderLater()
{
if (!m_update_pending)
{
m_update_pending = true;
QCoreApplication::postEvent(this,new QEvent(QEvent::UpdateRequest));
}
}
void QTestOffScreen::generateImg(QImage *tmp_img_pointer)
{
GLint viewPort[4]={0};
glGetIntegerv(GL_VIEWPORT,viewPort);
int win_width,win_height;
win_width = 1920;
win_height = 1080;
GLubyte *colorArr=new GLubyte[win_width*win_height*3];
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glReadBuffer (GL_FRONT);
int tmp_x,tmp_y;
tmp_x = 0;
tmp_y = 0;
glReadPixels(tmp_x,tmp_y,win_width,win_height,
GL_RGB,GL_UNSIGNED_BYTE,colorArr);
int winrows = tmp_img_pointer->height();
int wincols = tmp_img_pointer->width ();
for(int ii=0; ii < winrows * wincols * 3; ii ++)
{
if((colorArr[ii] <0)|(colorArr[ii] >255))
{ colorArr[ii] = 255; }
}
for(int j=0;j<winrows;j++)
for(int i=0;i<wincols;i++)
{
int index=(j*wincols+i)*3;
QRgb value=qRgb(colorArr[index+2],
colorArr[index+1],
colorArr[index ]);
tmp_img_pointer->setPixel(i,winrows-j-1,value);
}
delete colorArr;
}
主窗口.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "qtestoffscreen.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QTestOffScreen *scr;
private slots:
void ReceiveCurrentIndex(int);
};
#endif // MAINWINDOW_H
主窗口.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QSurfaceFormat format;
format.setSamples(1);
format.setRenderableType(QSurfaceFormat::OpenGL);
scr = new QTestOffScreen();
connect(scr,SIGNAL(doneImg(int)),this,SLOT(ReceiveCurrentIndex(int)));
scr->setFormat(format);
scr->setAnimating(true);//Start rendering animation here.
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::ReceiveCurrentIndex(int)
{
Sleep(100);
scr->renderLater();
}