我在做什么,简而言之:
MyItem
QQuickFramebufferObject
班级
MyItem
我有一个QQuickItem* sourceItem
属性,我可以从中获取纹理并将其绘制成三角形sourceItem
的图像到MyItem
。此图片有cache: false
update
MyItem
MyItem
个实例问题是MyItem
的某些实例没有得出任何结论:
有什么想法吗?
我的代码:
的main.cpp :
#include <QQmlApplicationEngine>
#include <QGuiApplication>
#include <QQuickFramebufferObject>
#include <QOpenGLFramebufferObject>
#include <QSGTextureProvider>
#include <QSGTexture>
#include <QQuickWindow>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
#include "propertyhelper.h" // this file is from http://syncor.blogspot.bg/2014/11/qt-auto-property.html
class MyItem : public QQuickFramebufferObject {
Q_OBJECT
AUTO_PROPERTY(QQuickItem*, sourceItem)
public:
Renderer *createRenderer() const;
};
class MyItemRenderer : public QQuickFramebufferObject::Renderer, protected QOpenGLFunctions {
public:
MyItemRenderer() {
initializeOpenGLFunctions();
m_program.addShaderFromSourceCode(QOpenGLShader::Vertex,
"in highp vec2 aPos;\
out highp vec2 vTexCoord;\
\
void main() {\
gl_Position = vec4(aPos, 0.0, 1.0);\
vTexCoord = aPos * .5 + .5;\
}"
);
m_program.addShaderFromSourceCode(QOpenGLShader::Fragment,
"in highp vec2 vTexCoord;\
out vec4 outputColor;\
uniform sampler2D uTex;\
\
void main() {\
outputColor = texture(uTex, vTexCoord);\
}"
);
m_program.link();
m_program.setUniformValue("uTex", 0);
createGeometry();
}
void synchronize(QQuickFramebufferObject* qqfbo){
auto item = (MyItem*)qqfbo;
m_window = item->window();
m_tex = item->sourceItem()->textureProvider()->texture();
}
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) {
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
return new QOpenGLFramebufferObject(size, format);
}
void paintGeometry() {
m_program.enableAttributeArray("aPos");
m_program.setAttributeArray("aPos", m_vertices.constData());
glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
m_program.disableAttributeArray("aPos");
}
void createGeometry() {
m_vertices << QVector2D(-1, -1);
m_vertices << QVector2D(1, -1);
m_vertices << QVector2D(-1, 1);
}
void render() {
glDisable(GL_DEPTH_TEST);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
m_program.bind();
glActiveTexture(GL_TEXTURE0);
m_tex->bind();
paintGeometry();
m_window->resetOpenGLState();
}
private:
QQuickWindow* m_window;
QVector<QVector2D> m_vertices;
QSGTexture* m_tex;
QOpenGLShaderProgram m_program;
};
QQuickFramebufferObject::Renderer *MyItem::createRenderer() const {
return new MyItemRenderer();
}
int main(int argc, char** argv) {
qmlRegisterType<MyItem>("MyItem", 1, 0, "MyItem");
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
#include "main.moc"
main.qml :
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
visible: true
id: window
width: 600
height: 600
Flow {
anchors.fill: parent
Repeater {
model: 36
delegate: MyItemWrapper {
width: 100
height: 100
}
}
}
}
MyItemWrapper.qml :
import QtQuick 2.5
import MyItem 1.0
Item {
Image {
x: -100000 // hide the sourceItem
id: sourceItem
layer.enabled: true
source: "https://images-na.ssl-images-amazon.com/images/M/MV5BMTg2MTMyMzU0M15BMl5BanBnXkFtZTgwOTU3ODk4NTE@._V1_SX300.jpg"
cache: false
function updateCppItemOnce() {
window.afterRendering.disconnect(updateCppItemOnce);
cppItem.update();
}
onStatusChanged: {
if (status == Image.Ready) {
window.afterRendering.connect(updateCppItemOnce);
}
}
}
MyItem {
sourceItem: sourceItem
anchors.fill: parent
id: cppItem
}
}
备注:
答案 0 :(得分:1)
我现在意识到,我只是连接到update()
信号,而不是我调用item->sourceItem()->textureProvider()->textureChanged()
的笨重方式。这样做,现在它就像一个魅力。
我仍然想知道为什么我原来的方式会失败,但是:)
答案 1 :(得分:0)
Gunnar Sletta在my bugreport中提供了解决方案作为评论。
我怀疑问题是你使用了'afterRendering&#39;信号。当在线程渲染循环上运行时,此信号将在渲染完成时触发,并且将在主线程上几乎立即调用插槽。根据线程渲染循环在图像完成加载时的位置,这意味着您可能会立即调用插槽。当场景图到达同步阶段时,处理节点的顺序是任意的,因此可以在图像之前处理一些节点,之后处理一些节点。在图像获得纹理之前处理的那些被获取为空并且在获得有效纹理之后处理的那些。
连接到afterSynchronization信号会更好,因为在图像的同步保证完成之后,这实际上会先触发。
确实,使用afterSynchronizing
解决了我的问题。