Qt 通过从项目中获取的纹理在QQuickFramebufferObject中绘制。除非我不断地重新绘制/更新,否则它将失败

Qt 通过从项目中获取的纹理在QQuickFramebufferObject中绘制。除非我不断地重新绘制/更新,否则它将失败,qt,opengl,qml,qtquick2,repaint,Qt,Opengl,Qml,Qtquick2,Repaint,简而言之,我的代码的作用是: 创建一个名为rect的简单矩形,图层为启用:true 将rect传递给名为itemSnapshotter 在synchronize中,将指针指向rect 在渲染中,绘制一个带有我所用纹理的矩形 当main.qml完成加载时,调用itemSnapshotter.update()这是第一次也是唯一一次 问题是QQFBO不会绘制任何内容,除非我取消注释render()末尾的update调用知道为什么吗? 我的代码: main.cpp: PassThrough.frag

简而言之,我的代码的作用是:

  • 创建一个名为
    rect
    的简单
    矩形
    ,图层为
    启用:true
  • rect
    传递给名为
    itemSnapshotter
  • synchronize
    中,将指针指向
    rect
  • 在渲染中,绘制一个带有我所用纹理的矩形
  • main.qml
    完成加载时,调用
    itemSnapshotter.update()这是第一次也是唯一一次
问题是QQFBO不会绘制任何内容,除非我取消注释
render()
末尾的
update
调用知道为什么吗?

我的代码:

main.cpp:

PassThrough.frag.glsl:

PassThrough.vert.glsl:


它正在保存指针。它也可能改变。另一件事:
synchronize()
和该
矩形的类似回调之间的顺序不清楚。这可能就是为什么要使用
QSGTextureProvider::textureChanged()
@Velkan:是的,它正在保存一个指针,编辑文章以反映这一点。回复:“它也可能改变。”-什么也可能改变?回复:“订单”-您注意到我在
onCompleted
中调用
update()
(调用
synchronize
)了吗?我不仅仅依靠QML的主动调用
update
textureChanged
看起来它可能会帮助我解决问题,谢谢。矩形的纹理可能会改变(我认为它甚至可能在不可见时消失)。在GUI线程中的
onCompleted
中调用
update()
。但是在渲染线程中调用了
synchronize()
。因此,中间存在某种队列,或者可能QuickItems被标记为要更新,以便在渲染线程和GUI线程之间进行下一次同步时对其进行处理。@Velkan:当然,矩形的纹理可能会更改。对我来说没问题。至于你的消息的其余部分,我不会发表评论,因为这只是猜测,似乎不会导致解决方案(除了“使用textureChanged”之外,我已经在努力了),这不是猜测。qt文档中有明确的说明,甚至有这两个线程的奇特图表,每个线程都有自己的颜色。
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QQuickFramebufferObject>
#include <QOpenGLFramebufferObject>
#include <QSGTextureProvider>
#include <QObject>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QQuickWindow>
#include <QOpenGLFunctions>
// propertyhelper.h is from http://syncor.blogspot.bg/2014/11/qt-auto-property.html
#include "propertyhelper.h"

class ItemSnapshotter : public QQuickFramebufferObject {
    Q_OBJECT

    AUTO_PROPERTY(QQuickItem*, sourceItem)

public:
    Renderer *createRenderer() const;
};

class ItemSnapshotterRenderer
    : public QObject
    , public QQuickFramebufferObject::Renderer
    , protected QOpenGLFunctions
{
    Q_OBJECT

public:
    ItemSnapshotterRenderer() {
        initializeOpenGLFunctions();
        initShader();
        createGeometry();
    }

    void createGeometry() {
        m_vertices << QVector2D(0, 0) << QVector2D(0, 1) << QVector2D(1, 1);
        m_vertices << QVector2D(0, 0) << QVector2D(1, 0) << QVector2D(1, 1);
    }

    void initShader() {
        m_shaderProgram.addShaderFromSourceFile(
            QOpenGLShader::Vertex, ":/PassThrough.vert.glsl");
        m_shaderProgram.addShaderFromSourceFile(
            QOpenGLShader::Fragment, ":/PassThrough.frag.glsl");
        m_shaderProgram.link();
        m_shaderProgram.bind();

        glActiveTexture(GL_TEXTURE0);
        m_shaderProgram.setUniformValue("uTex", 0);
    }

    void prepareShader() {
        m_shaderProgram.enableAttributeArray("aPos");
        m_shaderProgram.setAttributeArray("aPos", m_vertices.constData());
        m_shaderProgram.bind();
    }

    void render() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        prepareShader();
        m_tex->bind();
        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

        glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());

        m_window->resetOpenGLState();
        //update();
    }

    void synchronize(QQuickFramebufferObject* qqfbo){
        auto parentItem = (ItemSnapshotter*)qqfbo;

        m_window = parentItem->window();
        copyTexture(*parentItem);
    }

    void copyTexture(const ItemSnapshotter &srcItem) {
        QQuickItem* sourceItem = srcItem.sourceItem();
        QSGTextureProvider* sourceTexProvider = sourceItem->textureProvider();
        m_tex = sourceTexProvider->texture();
        GLenum err;
        while ((err = glGetError()) != GL_NO_ERROR) {
            qDebug("\tgl error: 0x%x", err, 0, 16);
        }
    }

    QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) {
        QOpenGLFramebufferObjectFormat format;
        format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); // TODO simpler format
        return new QOpenGLFramebufferObject(size, format);
    }

private:
    QOpenGLShaderProgram m_shaderProgram;
    QQuickWindow* m_window;
    QSGTexture* m_tex;
    QVector<QVector2D> m_vertices;
};

QQuickFramebufferObject::Renderer *ItemSnapshotter::createRenderer() const {
    return new ItemSnapshotterRenderer();
}

int main(int argc, char *argv[]) {
    qmlRegisterType<ItemSnapshotter>("ItemSnapshotter", 1, 0, "ItemSnapshotter");
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

#include "main.moc"
import QtQuick 2.6
import QtQuick.Window 2.2
import ItemSnapshotter 1.0

Window {
    visible: true
    width: 640
    height: 480

    Row {
        Rectangle {
            layer.enabled: true
            id: rect
            width: 100
            height: 100
            color: "red"
            border.color: "black"
        }

        ItemSnapshotter {
            id: itemSnapshotter
            sourceItem: rect
            width: sourceItem.width
            height: sourceItem.height
        }
    }

    Component.onCompleted: {
        itemSnapshotter.update();
    }
}
varying highp vec2 vTexCoord;
uniform sampler2D uTex;

void main() {
    gl_FragColor = texture2D(uTex, vTexCoord);
}
attribute highp vec2 aPos;
varying highp vec2 vTexCoord;

void main() {
    gl_Position = vec4(aPos, 0.0, 1.0);
    vTexCoord = aPos;
}