Anonymous
Обработанные изображения OpenGL не могут отображаться в окне QML
Сообщение
Anonymous » 13 мар 2025, 15:38
Я создал быстрый визуальный пользовательский компонент в C ++, который использует OpenGL для рендеринга. Но когда программа работает, я не вижу, что я рендерирую
Вопрос : как я могу увидеть изображение в окне?
Вот мой тестовый пример, который предназначен для визуализации локального изображения в окно.
Код: Выделить всё
#include
#include
#include"GLVideoWidget.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
QQmlApplicationEngine engine;
QObject::connect(
&engine,
&QQmlApplicationEngine::objectCreationFailed,
&app,
[]() { QCoreApplication::exit(-1); },
Qt::QueuedConnection);
qmlRegisterType("AvCom", 1, 0, "GLVideoWidget");
engine.loadFromModule("test", "Main");
return app.exec();
}
< /code>
glvideowidget.h
#ifndef PICTUREVIEW_H
#define PICTUREVIEW_H
#include
#include
#include
#include
#include
#include
#include
class VideoGLRenderer;
class GLVideoWidget : public QQuickItem
{
Q_OBJECT
QML_ELEMENT
public:
GLVideoWidget(QQuickItem *parent = nullptr);
~GLVideoWidget();
public slots:
void handleWindowChanged(QQuickWindow *window);
void guiSync();
void cleanup();
protected:
void releaseResources() override;
private:
VideoGLRenderer *vgl_renderer;
};
class QOpenGLShaderProgram;
class QOpenGLBuffer;
class QOpenGLVertexArrayObject;
class QOpenGLTexture;
class VideoGLRenderer : public QObject,
protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit VideoGLRenderer(QObject *parent = nullptr);
~VideoGLRenderer();
public slots:
void initRenderer();
void paint();
void setWindow(QQuickWindow *window);
protected:
private:
QQuickWindow *quick_window;
QOpenGLShaderProgram *shader_program;
QOpenGLBuffer *vbo;
QOpenGLBuffer *ebo;
QOpenGLVertexArrayObject *vao;
QOpenGLTexture *video_frame_texture;
QMutex mutex;
};
#endif // PICTUREVIEW_H
< /code>
glvideowidget.cpp
#include "GLVideoWidget.h"
#include
#include
#include
#include
#include
#include
#include
#include
GLVideoWidget::GLVideoWidget(QQuickItem *parent)
: QQuickItem(parent)
, vgl_renderer(nullptr)
{
setFlag(ItemHasContents, true);
connect(this, &QQuickItem::windowChanged, this, &GLVideoWidget::handleWindowChanged);
}
GLVideoWidget::~GLVideoWidget()
{
}
void GLVideoWidget::handleWindowChanged(QQuickWindow *window)
{
if (window) {
connect(window, &QQuickWindow::beforeSynchronizing, this, &GLVideoWidget::guiSync, Qt::DirectConnection);
connect(window, &QQuickWindow::sceneGraphInvalidated, this, &GLVideoWidget::cleanup, Qt::DirectConnection);
}
}
void GLVideoWidget::guiSync()
{
if (this->vgl_renderer == nullptr) {
this->vgl_renderer = new VideoGLRenderer(this);
connect(window(), &QQuickWindow::beforeRendering, this->vgl_renderer, &VideoGLRenderer::initRenderer,
Qt::DirectConnection);
connect(window(), &QQuickWindow::beforeRenderPassRecording, this->vgl_renderer, &VideoGLRenderer::paint,
Qt::DirectConnection);
}
this->vgl_renderer->setWindow(window());
}
void GLVideoWidget::cleanup()
{
delete this->vgl_renderer;
this->vgl_renderer = nullptr;
}
class VideoRenderer;
class CleanupJob : public QRunnable
{
public:
CleanupJob(VideoGLRenderer *renderer) : renderer(renderer) {}
void run() override
{
if (this->renderer) {
delete this->renderer;
}
}
private:
VideoGLRenderer *renderer;
};
void GLVideoWidget::releaseResources()
{
window()->scheduleRenderJob(new CleanupJob(this->vgl_renderer), QQuickWindow::BeforeSynchronizingStage);
this->vgl_renderer = nullptr;
}
VideoGLRenderer::VideoGLRenderer(QObject *parent) : quick_window(nullptr), shader_program(nullptr){}
VideoGLRenderer::~VideoGLRenderer() { }
void VideoGLRenderer::initRenderer()
{
QString vertexSource = R"(
#version 330 core
layout(location = 0) in vec3 vPosition;
layout(location = 1) in vec2 vTexCoord;
out vec2 TexCoord;
uniform mat4 zoomMatrix;
void main() {
gl_Position = zoomMatrix * vec4(vPosition, 1.0);
TexCoord = vTexCoord;
}
)";
QString fragSource = R"(
#version 330 core
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D frameTexture;
uniform bool IsTextureValid;
void main() {
if(!IsTextureValid)
{
FragColor = vec4(0.0,0.0,0.0,1.0);
} else {
FragColor = texture(frameTexture, TexCoord);
}
}
)";
if (this->shader_program != nullptr)
return;
QSGRendererInterface *rif = this->quick_window->rendererInterface();
Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::OpenGL);
initializeOpenGLFunctions();
this->shader_program = new QOpenGLShaderProgram();
if (!this->shader_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource))
qDebug() shader_program->log();
if (!this->shader_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragSource))
qDebug() shader_program->log();
if (!this->shader_program->link())
qDebug() shader_program->log();
QVector vertices = {
// positions // texture coords
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top left
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom left
1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom right
1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top right
};
QVector indices = {
0, 1, 2, 2, 3, 0,
};
this->vao = new QOpenGLVertexArrayObject();
this->vbo = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
this->ebo = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
this->vao->create();
this->vbo->create();
this->ebo->create();
this->vao->bind();
this->vbo->bind();
this->ebo->bind();
this->vbo->allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
this->ebo->allocate(indices.constData(), indices.size() * sizeof(GLuint));
this->shader_program->bind();
this->shader_program->setAttributeBuffer("vPosition", GL_FLOAT, 0, 3, 5 * sizeof(GLfloat));
this->shader_program->enableAttributeArray(0);
this->shader_program->setAttributeBuffer("vTexCoord", GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));
this->shader_program->enableAttributeArray(1);
this->vao->release();
this->video_frame_texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
this->video_frame_texture->setMagnificationFilter(QOpenGLTexture::Linear);
this->video_frame_texture->setMinificationFilter(QOpenGLTexture::Linear);
this->video_frame_texture->setWrapMode(QOpenGLTexture::Repeat);
}
void VideoGLRenderer::paint()
{
bool isTextureValid;
QMatrix4x4 zoom;
this->quick_window->beginExternalCommands();
glDisable(GL_DEPTH_TEST);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
//The path needs to be replaced
QImage img("E:/qt_project/qmlTestProject/test/fufu.png");
if (img.isNull()) {
return;
}
video_frame_texture->destroy();
video_frame_texture->create();
video_frame_texture->setData(img.mirrored());
isTextureValid = true;
this->shader_program->bind();
this->shader_program->setUniformValue("IsTextureValid", isTextureValid);
this->vao->bind();
if (isTextureValid) {
this->video_frame_texture->bind(0);
}
this->shader_program->setUniformValue("zoomMatrix", zoom);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
this->vao->release();
this->shader_program->release();
if (isTextureValid)
this->video_frame_texture->release();
this->quick_window->endExternalCommands();
}
void VideoGLRenderer::setWindow(QQuickWindow *window) { this->quick_window = window; }
< /code>
main.qml
import QtQuick
import QtQuick.Dialogs
import QtQuick.Controls 2.3
import QtCore
import AvCom
ApplicationWindow {
id: appWindow
title: qsTr("MavPlayer")
visible: true
width: 1600
height: 920
color: 'white'
menuBar: MenuBar {
Menu {
title: qsTr("file")
MenuItem {
text: qsTr("open")
}
}
}
GLVideoWidget {
id: videoView
anchors.left: appWindow.left
anchors.right: appWindow.right
anchors.top: appWindow.menuBar.bottom
anchors.bottom: play_progress.top
anchors.leftMargin: 0
anchors.rightMargin: 0
anchors.topMargin: 5
anchors.bottomMargin: 5
}
Slider {
id: play_progress
value: 0.5
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: displayControlBar.top
anchors.leftMargin: 0
anchors.rightMargin: 0
anchors.bottomMargin: 1
}
Rectangle {
id: displayControlBar
height: 50
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.leftMargin: 0
anchors.rightMargin: 0
anchors.bottomMargin: 20
}
}
QT -версия, которую я использую, qt6.8.0
stides 11
Подробнее здесь:
https://stackoverflow.com/questions/795 ... qml-window
1741869480
Anonymous
Я создал быстрый визуальный пользовательский компонент в C ++, который использует OpenGL для рендеринга. Но когда программа работает, я не вижу, что я рендерирую [b] Вопрос [/b]: как я могу увидеть изображение в окне? Вот мой тестовый пример, который предназначен для визуализации локального изображения в окно.[code]#include #include #include"GLVideoWidget.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); QQmlApplicationEngine engine; QObject::connect( &engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); qmlRegisterType("AvCom", 1, 0, "GLVideoWidget"); engine.loadFromModule("test", "Main"); return app.exec(); } < /code> glvideowidget.h #ifndef PICTUREVIEW_H #define PICTUREVIEW_H #include #include #include #include #include #include #include class VideoGLRenderer; class GLVideoWidget : public QQuickItem { Q_OBJECT QML_ELEMENT public: GLVideoWidget(QQuickItem *parent = nullptr); ~GLVideoWidget(); public slots: void handleWindowChanged(QQuickWindow *window); void guiSync(); void cleanup(); protected: void releaseResources() override; private: VideoGLRenderer *vgl_renderer; }; class QOpenGLShaderProgram; class QOpenGLBuffer; class QOpenGLVertexArrayObject; class QOpenGLTexture; class VideoGLRenderer : public QObject, protected QOpenGLFunctions { Q_OBJECT public: explicit VideoGLRenderer(QObject *parent = nullptr); ~VideoGLRenderer(); public slots: void initRenderer(); void paint(); void setWindow(QQuickWindow *window); protected: private: QQuickWindow *quick_window; QOpenGLShaderProgram *shader_program; QOpenGLBuffer *vbo; QOpenGLBuffer *ebo; QOpenGLVertexArrayObject *vao; QOpenGLTexture *video_frame_texture; QMutex mutex; }; #endif // PICTUREVIEW_H < /code> glvideowidget.cpp #include "GLVideoWidget.h" #include #include #include #include #include #include #include #include GLVideoWidget::GLVideoWidget(QQuickItem *parent) : QQuickItem(parent) , vgl_renderer(nullptr) { setFlag(ItemHasContents, true); connect(this, &QQuickItem::windowChanged, this, &GLVideoWidget::handleWindowChanged); } GLVideoWidget::~GLVideoWidget() { } void GLVideoWidget::handleWindowChanged(QQuickWindow *window) { if (window) { connect(window, &QQuickWindow::beforeSynchronizing, this, &GLVideoWidget::guiSync, Qt::DirectConnection); connect(window, &QQuickWindow::sceneGraphInvalidated, this, &GLVideoWidget::cleanup, Qt::DirectConnection); } } void GLVideoWidget::guiSync() { if (this->vgl_renderer == nullptr) { this->vgl_renderer = new VideoGLRenderer(this); connect(window(), &QQuickWindow::beforeRendering, this->vgl_renderer, &VideoGLRenderer::initRenderer, Qt::DirectConnection); connect(window(), &QQuickWindow::beforeRenderPassRecording, this->vgl_renderer, &VideoGLRenderer::paint, Qt::DirectConnection); } this->vgl_renderer->setWindow(window()); } void GLVideoWidget::cleanup() { delete this->vgl_renderer; this->vgl_renderer = nullptr; } class VideoRenderer; class CleanupJob : public QRunnable { public: CleanupJob(VideoGLRenderer *renderer) : renderer(renderer) {} void run() override { if (this->renderer) { delete this->renderer; } } private: VideoGLRenderer *renderer; }; void GLVideoWidget::releaseResources() { window()->scheduleRenderJob(new CleanupJob(this->vgl_renderer), QQuickWindow::BeforeSynchronizingStage); this->vgl_renderer = nullptr; } VideoGLRenderer::VideoGLRenderer(QObject *parent) : quick_window(nullptr), shader_program(nullptr){} VideoGLRenderer::~VideoGLRenderer() { } void VideoGLRenderer::initRenderer() { QString vertexSource = R"( #version 330 core layout(location = 0) in vec3 vPosition; layout(location = 1) in vec2 vTexCoord; out vec2 TexCoord; uniform mat4 zoomMatrix; void main() { gl_Position = zoomMatrix * vec4(vPosition, 1.0); TexCoord = vTexCoord; } )"; QString fragSource = R"( #version 330 core in vec2 TexCoord; out vec4 FragColor; uniform sampler2D frameTexture; uniform bool IsTextureValid; void main() { if(!IsTextureValid) { FragColor = vec4(0.0,0.0,0.0,1.0); } else { FragColor = texture(frameTexture, TexCoord); } } )"; if (this->shader_program != nullptr) return; QSGRendererInterface *rif = this->quick_window->rendererInterface(); Q_ASSERT(rif->graphicsApi() == QSGRendererInterface::OpenGL); initializeOpenGLFunctions(); this->shader_program = new QOpenGLShaderProgram(); if (!this->shader_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource)) qDebug() shader_program->log(); if (!this->shader_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) qDebug() shader_program->log(); if (!this->shader_program->link()) qDebug() shader_program->log(); QVector vertices = { // positions // texture coords -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top left -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom left 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, // bottom right 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top right }; QVector indices = { 0, 1, 2, 2, 3, 0, }; this->vao = new QOpenGLVertexArrayObject(); this->vbo = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); this->ebo = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer); this->vao->create(); this->vbo->create(); this->ebo->create(); this->vao->bind(); this->vbo->bind(); this->ebo->bind(); this->vbo->allocate(vertices.constData(), vertices.size() * sizeof(GLfloat)); this->ebo->allocate(indices.constData(), indices.size() * sizeof(GLuint)); this->shader_program->bind(); this->shader_program->setAttributeBuffer("vPosition", GL_FLOAT, 0, 3, 5 * sizeof(GLfloat)); this->shader_program->enableAttributeArray(0); this->shader_program->setAttributeBuffer("vTexCoord", GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat)); this->shader_program->enableAttributeArray(1); this->vao->release(); this->video_frame_texture = new QOpenGLTexture(QOpenGLTexture::Target2D); this->video_frame_texture->setMagnificationFilter(QOpenGLTexture::Linear); this->video_frame_texture->setMinificationFilter(QOpenGLTexture::Linear); this->video_frame_texture->setWrapMode(QOpenGLTexture::Repeat); } void VideoGLRenderer::paint() { bool isTextureValid; QMatrix4x4 zoom; this->quick_window->beginExternalCommands(); glDisable(GL_DEPTH_TEST); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); //The path needs to be replaced QImage img("E:/qt_project/qmlTestProject/test/fufu.png"); if (img.isNull()) { return; } video_frame_texture->destroy(); video_frame_texture->create(); video_frame_texture->setData(img.mirrored()); isTextureValid = true; this->shader_program->bind(); this->shader_program->setUniformValue("IsTextureValid", isTextureValid); this->vao->bind(); if (isTextureValid) { this->video_frame_texture->bind(0); } this->shader_program->setUniformValue("zoomMatrix", zoom); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); this->vao->release(); this->shader_program->release(); if (isTextureValid) this->video_frame_texture->release(); this->quick_window->endExternalCommands(); } void VideoGLRenderer::setWindow(QQuickWindow *window) { this->quick_window = window; } < /code> main.qml import QtQuick import QtQuick.Dialogs import QtQuick.Controls 2.3 import QtCore import AvCom ApplicationWindow { id: appWindow title: qsTr("MavPlayer") visible: true width: 1600 height: 920 color: 'white' menuBar: MenuBar { Menu { title: qsTr("file") MenuItem { text: qsTr("open") } } } GLVideoWidget { id: videoView anchors.left: appWindow.left anchors.right: appWindow.right anchors.top: appWindow.menuBar.bottom anchors.bottom: play_progress.top anchors.leftMargin: 0 anchors.rightMargin: 0 anchors.topMargin: 5 anchors.bottomMargin: 5 } Slider { id: play_progress value: 0.5 anchors.left: parent.left anchors.right: parent.right anchors.bottom: displayControlBar.top anchors.leftMargin: 0 anchors.rightMargin: 0 anchors.bottomMargin: 1 } Rectangle { id: displayControlBar height: 50 anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom anchors.leftMargin: 0 anchors.rightMargin: 0 anchors.bottomMargin: 20 } } [/code] QT -версия, которую я использую, qt6.8.0 [b] [/b] stides 11 Подробнее здесь: [url]https://stackoverflow.com/questions/79505928/opengl-rendered-images-cannot-be-displayed-in-qml-window[/url]