Несмотря на простоту того, что он делает, OpenGL все еще сбивает меня с толку, но я начинаю узнавать, как он работает.
Я ищу минимальный пример рендеринга за кадром, чтобы начать.
Мое приложение должно принимать набор треугольников и информацию о том, как расположить их относительно камеры, и сохранять результат рендеринга в файл изображения. Пока без освещения, материалов и постобработки.
Я смотрел учебные пособия по созданию внеэкранных контекстов, созданию FBO, рендерингу в текстуру и т. д. Я не возражаю против использования QT, поскольку он удобно предоставляет инструменты OpenGL, окна и QImage. Насколько я понимаю, чтобы иметь возможность выполнять обработку изображения на визуализируемом изображении, вам нужно настроить цель рендеринга как текстуру, затем использовать шейдеры и, наконец, прочитать текстуру в массив.
Попытка собрать вещи воедино никогда не приводила меня к хорошей отправной точке. Я либо застреваю с настройкой зависимостей, получая черный экран, либо смотрю на проекты, которые делают слишком много вещей помимо того, что мне нужно.
Обновление 1: вроде заработало.
#include <QtGui/QGuiApplication>
#include <QtGui/QSurfaceFormat>
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLFunctions_4_3_Core>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLShaderProgram>
#include <QDebug>
#include <QImage>
#include <QOpenGLBuffer>
int main(int argc, char* argv[])
{
QGuiApplication 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);
QOpenGLFunctions_4_3_Core f;
if(!f.initializeOpenGLFunctions()) return -3;
qDebug() << QString::fromLatin1((const char*)f.glGetString(GL_VERSION));
QSize vpSize = QSize(100, 200);
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\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\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);
f.glClearColor(0.3f, 0.0f, 0.7f, 1.0f);
f.glClear(GL_COLOR_BUFFER_BIT);
f.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!!");
}
return 0;
}
Сохраненное изображение имеет тот же размер, что и FBO, цвет соответствует заданному в glClearColor, но треугольник не визуализируется. Что мне не хватает?
glReadPixels
просто считывает содержимое экрана в память процессора, оттуда вам нужно закодировать его как изображение ... для нового API вы можете загрузить текстуру аналогично тому, как она хранится ... - person Spektre   schedule 08.12.2019glReadPixels
, поскольку вам нужно скопировать изображение обратно на сторону процессора в любом случае... - person Spektre   schedule 09.12.2019