使用 QT 的最小 OpenGL 离屏渲染
Minimal OpenGL offscreen rendering using QT
我正在尝试制作一个简单的屏幕外渲染器,以使用 QT 生成一堆图像文件。周围有很多示例,但我还没有找到任何处理这种一次性渲染的方法,没有循环也没有可见的 window。另外,QT 为您提供了方便的包装器,这很棒,但另一方面,使用 C++glew+glfw 编写的示例变得更加困难。
我尝试使用 this to set the offscreen context and it works. After creating an FBO and rendering(like here) 图像内部没有绘制三角形 (fbo->ToImage)。
我当前的代码只是两个代码的混合:
#include <QtGui/QSurfaceFormat>
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLShaderProgram>
#include <QApplication>
#include <QDebug>
#include <QImage>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
QSurfaceFormat surfaceFormat;
surfaceFormat.setMajorVersion(4);
surfaceFormat.setMinorVersion(3);
QOpenGLContext openGLContext;
openGLContext.setFormat(surfaceFormat);
openGLContext.create();
if(!openGLContext.isValid()) return -1;
QOffscreenSurface surface;
surface.setFormat(surfaceFormat);
surface.create();
if(!surface.isValid()) return -2;
openGLContext.makeCurrent(&surface);
QSize vpSize = QSize(300, 300);
qDebug("Hi");
QOpenGLFramebufferObjectFormat fboFormat;
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
QOpenGLFramebufferObject fbo(vpSize, fboFormat);
fbo.bind();
static const float vertexPositions[] = {
-0.8f, -0.8f, 0.0f,
0.8f, -0.8f, 0.0f,
0.0f, 0.8f, 0.0f
};
static const float vertexColors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
QOpenGLBuffer vertexPositionBuffer(QOpenGLBuffer::VertexBuffer);
vertexPositionBuffer.create();
vertexPositionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
vertexPositionBuffer.bind();
vertexPositionBuffer.allocate(vertexPositions, 9 * sizeof(float));
QOpenGLBuffer vertexColorBuffer(QOpenGLBuffer::VertexBuffer);
vertexColorBuffer.create();
vertexColorBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
vertexColorBuffer.bind();
vertexColorBuffer.allocate(vertexColors, 9 * sizeof(float));
QOpenGLShaderProgram program;
program.addShaderFromSourceCode(QOpenGLShader::Vertex,
"#version 330\r\n"
"in vec3 position;\n"
"in vec3 color;\n"
"out vec3 fragColor;\n"
"void main() {\n"
" fragColor = color;\n"
" gl_Position = vec4(position, 1.0);\n"
"}\n"
);
program.addShaderFromSourceCode(QOpenGLShader::Fragment,
"#version 330\r\n"
"in vec3 fragColor;\n"
"out vec4 color;\n"
"void main() {\n"
" color = vec4(fragColor, 1.0);\n"
"}\n"
);
program.link();
program.bind();
vertexPositionBuffer.bind();
program.enableAttributeArray("position");
program.setAttributeBuffer("position", GL_FLOAT, 0, 3);
vertexColorBuffer.bind();
program.enableAttributeArray("color");
program.setAttributeBuffer("color", GL_FLOAT, 0, 3);
openGLContext.functions()->glClearColor(0.3f, 0.0f, 0.7f, 1.0f);
openGLContext.functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
openGLContext.functions()->glDrawArrays(GL_TRIANGLES, 0, 3);
program.disableAttributeArray("position");
program.disableAttributeArray("color");
program.release();
fbo.release();
qDebug("FBO released");
QImage im = fbo.toImage();
if (im.save("asd.png")){
qDebug("Image saved!!");
}
a.exec();
}
关于如何将屏幕外部分与绘图部分放在一起的任何想法?
更新 1:
#include <QGuiApplication>
#include <QOffscreenSurface>
#include <QOpenGLFunctions>
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QDebug>
#include <QImage>
#include <QLoggingCategory>
int main(int argc, char* argv[])
{
QGuiApplication a(argc, argv);
// QLoggingCategory::setFilterRules("qt.qpa.gl=true");
// =======CONTEXT SETUP======
// Set OpenGL version to use
QSurfaceFormat surfaceFormat;
surfaceFormat.setMajorVersion(4);
surfaceFormat.setMinorVersion(3);
QOpenGLContext openGLContext;
openGLContext.setFormat(surfaceFormat);
openGLContext.create();
if(!openGLContext.isValid()) qDebug("Unable to create context");
QOffscreenSurface surface;
surface.setFormat(surfaceFormat);
surface.create();
if(!surface.isValid()) qDebug("Unable to create the Offscreen surface");
openGLContext.makeCurrent(&surface);
// Viewport size
QSize vpSize = QSize(300, 300);
QOpenGLFramebufferObjectFormat fboFormat;
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
QOpenGLFramebufferObject fbo(vpSize, fboFormat);
openGLContext.functions()->glViewport(0,0,vpSize.width(), vpSize.height());
fbo.bind();
// ========GEOMEETRY SETUP========
static const float vertexPositions[] = {
-1.0f, -1.0f,
-0.0f, 1.0f,
1.0f, -1.0f,
};
static const float vertexColors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
QOpenGLBuffer vertexPositionBuffer(QOpenGLBuffer::VertexBuffer);
vertexPositionBuffer.create();
vertexPositionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
vertexPositionBuffer.bind();
vertexPositionBuffer.allocate(vertexPositions, 6 * sizeof(float));
QOpenGLBuffer vertexColorBuffer(QOpenGLBuffer::VertexBuffer);
vertexColorBuffer.create();
vertexColorBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
vertexColorBuffer.bind();
vertexColorBuffer.allocate(vertexColors, 9 * sizeof(float));
QOpenGLShaderProgram program;
program.addShaderFromSourceCode(QOpenGLShader::Vertex,
"#version 330\r\n"
"in vec2 position;\n"
"in vec3 color;\n"
"out vec3 fragColor;\n"
"void main() {\n"
" fragColor = color;\n"
" gl_Position = vec4(position, 0.0, 1.0);\n"
"}\n"
);
program.addShaderFromSourceCode(QOpenGLShader::Fragment,
"#version 330\r\n"
"in vec3 fragColor;\n"
"out vec4 color;\n"
"void main() {\n"
" color = vec4(fragColor, 1.0);\n"
"}\n"
);
program.link();
program.bind();
QOpenGLVertexArrayObject vao;
vao.create();
vao.bind();
vertexPositionBuffer.bind();
program.enableAttributeArray("position");
program.setAttributeBuffer("position", GL_FLOAT, 0, 2);
vertexColorBuffer.bind();
program.enableAttributeArray("color");
program.setAttributeBuffer("color", GL_FLOAT, 0, 3);
// ==============DRAWING TO THE FBO============
openGLContext.functions()->glClearColor(0.3f, 0.0f, 0.7f, 1.0f);
openGLContext.functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
openGLContext.functions()->glDrawArrays(GL_TRIANGLES, 0, 3);
// =============CLEANUP================== maybe not necessary
program.disableAttributeArray("position");
program.disableAttributeArray("color");
program.release();
fbo.release();
// ========SAVE IMAGE===========
QImage im = fbo.toImage();
if (im.save("asd.png")){
qDebug("Image saved!!");
}
a.quit();
}
感谢 G.M 的提示。
这是一个工作代码,可以为任何感兴趣的人保存彩色三角形的图像。
我怀疑问题只是您获得的是 4.3 核心配置文件,但不是 creating/using vertex array object。绑定着色器程序后立即创建一个 VAO 应该就足够了,所以更改...
program.link();
program.bind();
到...
program.link();
program.bind();
QOpenGLVertexArrayObject vao;
vao.create();
vao.bind();
(您还需要在源文件的顶部添加 #include <QOpenGLVertexArrayObject>
。)
另请注意,错误检查很重要。考虑使用 glGetError
or perhaps a debug context.
我正在尝试制作一个简单的屏幕外渲染器,以使用 QT 生成一堆图像文件。周围有很多示例,但我还没有找到任何处理这种一次性渲染的方法,没有循环也没有可见的 window。另外,QT 为您提供了方便的包装器,这很棒,但另一方面,使用 C++glew+glfw 编写的示例变得更加困难。
我尝试使用 this to set the offscreen context and it works. After creating an FBO and rendering(like here) 图像内部没有绘制三角形 (fbo->ToImage)。
我当前的代码只是两个代码的混合:
#include <QtGui/QSurfaceFormat>
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLShaderProgram>
#include <QApplication>
#include <QDebug>
#include <QImage>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
QSurfaceFormat surfaceFormat;
surfaceFormat.setMajorVersion(4);
surfaceFormat.setMinorVersion(3);
QOpenGLContext openGLContext;
openGLContext.setFormat(surfaceFormat);
openGLContext.create();
if(!openGLContext.isValid()) return -1;
QOffscreenSurface surface;
surface.setFormat(surfaceFormat);
surface.create();
if(!surface.isValid()) return -2;
openGLContext.makeCurrent(&surface);
QSize vpSize = QSize(300, 300);
qDebug("Hi");
QOpenGLFramebufferObjectFormat fboFormat;
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
QOpenGLFramebufferObject fbo(vpSize, fboFormat);
fbo.bind();
static const float vertexPositions[] = {
-0.8f, -0.8f, 0.0f,
0.8f, -0.8f, 0.0f,
0.0f, 0.8f, 0.0f
};
static const float vertexColors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
QOpenGLBuffer vertexPositionBuffer(QOpenGLBuffer::VertexBuffer);
vertexPositionBuffer.create();
vertexPositionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
vertexPositionBuffer.bind();
vertexPositionBuffer.allocate(vertexPositions, 9 * sizeof(float));
QOpenGLBuffer vertexColorBuffer(QOpenGLBuffer::VertexBuffer);
vertexColorBuffer.create();
vertexColorBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
vertexColorBuffer.bind();
vertexColorBuffer.allocate(vertexColors, 9 * sizeof(float));
QOpenGLShaderProgram program;
program.addShaderFromSourceCode(QOpenGLShader::Vertex,
"#version 330\r\n"
"in vec3 position;\n"
"in vec3 color;\n"
"out vec3 fragColor;\n"
"void main() {\n"
" fragColor = color;\n"
" gl_Position = vec4(position, 1.0);\n"
"}\n"
);
program.addShaderFromSourceCode(QOpenGLShader::Fragment,
"#version 330\r\n"
"in vec3 fragColor;\n"
"out vec4 color;\n"
"void main() {\n"
" color = vec4(fragColor, 1.0);\n"
"}\n"
);
program.link();
program.bind();
vertexPositionBuffer.bind();
program.enableAttributeArray("position");
program.setAttributeBuffer("position", GL_FLOAT, 0, 3);
vertexColorBuffer.bind();
program.enableAttributeArray("color");
program.setAttributeBuffer("color", GL_FLOAT, 0, 3);
openGLContext.functions()->glClearColor(0.3f, 0.0f, 0.7f, 1.0f);
openGLContext.functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
openGLContext.functions()->glDrawArrays(GL_TRIANGLES, 0, 3);
program.disableAttributeArray("position");
program.disableAttributeArray("color");
program.release();
fbo.release();
qDebug("FBO released");
QImage im = fbo.toImage();
if (im.save("asd.png")){
qDebug("Image saved!!");
}
a.exec();
}
关于如何将屏幕外部分与绘图部分放在一起的任何想法?
更新 1:
#include <QGuiApplication>
#include <QOffscreenSurface>
#include <QOpenGLFunctions>
#include <QOpenGLFramebufferObject>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QDebug>
#include <QImage>
#include <QLoggingCategory>
int main(int argc, char* argv[])
{
QGuiApplication a(argc, argv);
// QLoggingCategory::setFilterRules("qt.qpa.gl=true");
// =======CONTEXT SETUP======
// Set OpenGL version to use
QSurfaceFormat surfaceFormat;
surfaceFormat.setMajorVersion(4);
surfaceFormat.setMinorVersion(3);
QOpenGLContext openGLContext;
openGLContext.setFormat(surfaceFormat);
openGLContext.create();
if(!openGLContext.isValid()) qDebug("Unable to create context");
QOffscreenSurface surface;
surface.setFormat(surfaceFormat);
surface.create();
if(!surface.isValid()) qDebug("Unable to create the Offscreen surface");
openGLContext.makeCurrent(&surface);
// Viewport size
QSize vpSize = QSize(300, 300);
QOpenGLFramebufferObjectFormat fboFormat;
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
QOpenGLFramebufferObject fbo(vpSize, fboFormat);
openGLContext.functions()->glViewport(0,0,vpSize.width(), vpSize.height());
fbo.bind();
// ========GEOMEETRY SETUP========
static const float vertexPositions[] = {
-1.0f, -1.0f,
-0.0f, 1.0f,
1.0f, -1.0f,
};
static const float vertexColors[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
QOpenGLBuffer vertexPositionBuffer(QOpenGLBuffer::VertexBuffer);
vertexPositionBuffer.create();
vertexPositionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
vertexPositionBuffer.bind();
vertexPositionBuffer.allocate(vertexPositions, 6 * sizeof(float));
QOpenGLBuffer vertexColorBuffer(QOpenGLBuffer::VertexBuffer);
vertexColorBuffer.create();
vertexColorBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
vertexColorBuffer.bind();
vertexColorBuffer.allocate(vertexColors, 9 * sizeof(float));
QOpenGLShaderProgram program;
program.addShaderFromSourceCode(QOpenGLShader::Vertex,
"#version 330\r\n"
"in vec2 position;\n"
"in vec3 color;\n"
"out vec3 fragColor;\n"
"void main() {\n"
" fragColor = color;\n"
" gl_Position = vec4(position, 0.0, 1.0);\n"
"}\n"
);
program.addShaderFromSourceCode(QOpenGLShader::Fragment,
"#version 330\r\n"
"in vec3 fragColor;\n"
"out vec4 color;\n"
"void main() {\n"
" color = vec4(fragColor, 1.0);\n"
"}\n"
);
program.link();
program.bind();
QOpenGLVertexArrayObject vao;
vao.create();
vao.bind();
vertexPositionBuffer.bind();
program.enableAttributeArray("position");
program.setAttributeBuffer("position", GL_FLOAT, 0, 2);
vertexColorBuffer.bind();
program.enableAttributeArray("color");
program.setAttributeBuffer("color", GL_FLOAT, 0, 3);
// ==============DRAWING TO THE FBO============
openGLContext.functions()->glClearColor(0.3f, 0.0f, 0.7f, 1.0f);
openGLContext.functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
openGLContext.functions()->glDrawArrays(GL_TRIANGLES, 0, 3);
// =============CLEANUP================== maybe not necessary
program.disableAttributeArray("position");
program.disableAttributeArray("color");
program.release();
fbo.release();
// ========SAVE IMAGE===========
QImage im = fbo.toImage();
if (im.save("asd.png")){
qDebug("Image saved!!");
}
a.quit();
}
感谢 G.M 的提示。 这是一个工作代码,可以为任何感兴趣的人保存彩色三角形的图像。
我怀疑问题只是您获得的是 4.3 核心配置文件,但不是 creating/using vertex array object。绑定着色器程序后立即创建一个 VAO 应该就足够了,所以更改...
program.link();
program.bind();
到...
program.link();
program.bind();
QOpenGLVertexArrayObject vao;
vao.create();
vao.bind();
(您还需要在源文件的顶部添加 #include <QOpenGLVertexArrayObject>
。)
另请注意,错误检查很重要。考虑使用 glGetError
or perhaps a debug context.