【问题标题】:Issue with drawing an Qml Item with raw OpenGL calls使用原始 OpenGL 调用绘制 Qml 项目的问题
【发布时间】:2015-03-20 04:22:56
【问题描述】:

我想使用原始 OpenGL 调用在 QtQuick 场景中绘制单个项目。我决定采用this question 中建议的方法。

我创建了一个源自QQuickFramebufferObject 的 Qt Quick 项目,并将其作为 Renderer 暴露给 QML:(代码基于 Qt 示例:Scene Graph - Rendering FBOs

class FboInSGRenderer : public QQuickFramebufferObject {
    Q_OBJECT
public:
    Renderer *createRenderer() const;
};

源文件:

class LogoInFboRenderer : public QQuickFramebufferObject::Renderer {
    public:
        LogoInFboRenderer() { }

        void render() {
            int width = 1, height = 1;
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glColor4f(0.0, 1.0, 0.0, 0.8);
            glBegin(GL_QUADS);
            glVertex2f(0, 0);
            glVertex2f(width, 0);
            glVertex2f(width, height);
            glVertex2f(0, height);
            glEnd();

            glLineWidth(2.5);
            glColor4f(0.0, 0.0, 0.0, 1.0);
            glBegin(GL_LINES);
            glVertex2f(0, 0);
            glVertex2f(width, height);
            glVertex2f(width, 0);
            glVertex2f(0, height);
            glEnd();

            update();
        }

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

QQuickFramebufferObject::Renderer *FboInSGRenderer::createRenderer() const {
    return new LogoInFboRenderer();
}

在 Qml 中我按如下方式使用它:

import QtQuick 2.4
import SceneGraphRendering 1.0

Rectangle {
    width: 400
    height: 400
    color: "purple"
    Renderer {
        id: renderer
        anchors.fill: parent
    }
}

我期待看到渲染的“X”会填满整个场景,但结果却如下所示:

其他实验似乎证实了绘制的形状总是其大小(宽度/高度)除以 2。

我还检查了createFramebufferObject 中的size 参数值是否正确。

查看文档让我找到了QQuickFramebufferObject 类中的属性textureFollowsItemSize,但默认设置为true

我做错了什么还是应该将此行为视为 Qt 错误?

【问题讨论】:

  • 我不知道 QQuick,但是 OpenGL 并且我没有看到您设置了相机(投影或模型视图)或视口。如果您使用默认的 opengl 相机,它会向下看负 z 轴。因此,当绘制正 x 和 y 象限时,我会期望您显示的结果(请记住,在 opengl 中,y 是颠倒的)。例如,要在帧缓冲区中渲染一些 2d 项目,我将在 z 方向设置一个正交相机和一个边界为 [0,0] 到 [pixels_width,pixels_height] 的 glViewport。
  • 我已经使用了您的代码 - 在我的情况下,绿色的东西只呈现一次。这是为什么呢?

标签: qt opengl qml qt-quick qtquick2


【解决方案1】:

绘制的矩形是您预期大小的一半,因为默认坐标范围是 [-1, 1],而不是您的代码假设的 [0, 1]。如果要使用 [0, 1] 比例,则应适当设置投影矩阵:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);

【讨论】:

  • 谢谢!它解决了我的问题,尽管我遇到了另一个问题:当我调整包含该项目的窗口大小时,帧缓冲区对象被工件填充 - 项目不是正确的渲染器。我会尝试进一步调查,如果找不到答案,我可能会发布新问题。
  • 关于窗口大小调整的新问题,您找到解决方案了吗?
【解决方案2】:

正如 Qt 文档所说:"Warning: It is crucial that OpenGL operations and interaction with the scene graph happens exclusively on the rendering thread, primarily during the updatePaintNode() call. The best rule of thumb is to only use classes with the "QSG" prefix inside the QQuickItem::updatePaintNode() function." 我是这样做的:

*.h

class MyQuickItem : public QQuickItem
{
    Q_OBJECT
public:
    MyQuickItem();
    ~MyQuickItem();

protected:
    QSGNode *updatePaintNode(QSGNode * oldNode, UpdatePaintNodeData * updatePaintNodeData);
    QSGNode *addNode(QSGGeometry *geometry, const QColor &color);
};

*.cpp

MyQuickItem::MyQuickItem()
{
    setFlag(QQuickItem::ItemHasContents,true);
}

MyQuickItem::~MyQuickItem()
{

}

QSGNode *MyQuickItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData)
{
    Q_UNUSED(updatePaintNodeData)

    QSGTransformNode *root = static_cast<QSGTransformNode *>(oldNode);
    if(!root) root = new QSGTransformNode;
    QSGNode *node;
    QSGGeometry *geometry;

    QSGSimpleRectNode *rect = new QSGSimpleRectNode();
    rect->setColor(Qt::green);
    rect->setRect(boundingRect());
    root->appendChildNode(rect);

    geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2);
    geometry->setDrawingMode(GL_LINES);
    geometry->setLineWidth(5.0);
    geometry->vertexDataAsPoint2D()[0].set(x(), y());
    geometry->vertexDataAsPoint2D()[1].set(width(), height());
    node = addNode(geometry,Qt::blue);
    root->appendChildNode(node);

    geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2);
    geometry->setDrawingMode(GL_LINES);
    geometry->setLineWidth(5.0);
    geometry->vertexDataAsPoint2D()[0].set(width(), y());
    geometry->vertexDataAsPoint2D()[1].set(x(), height());
    node = addNode(geometry,Qt::blue);
    root->appendChildNode(node);

    return root;
}

QSGNode *MyQuickItem::addNode(QSGGeometry *geometry, const QColor &color)
{
    QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
    material->setColor(color);
    QSGGeometryNode *node = new QSGGeometryNode;
    node->setGeometry(geometry);
    node->setFlag(QSGNode::OwnsGeometry);
    node->setMaterial(material);
    node->setFlag(QSGNode::OwnsMaterial);
    return node;
}

ma​​in.cpp

qmlRegisterType<MyQuickItem>("MyObjects", 1, 0, "MyObject");

及用法:

import QtQuick 2.3
import QtQuick.Window 2.2
import MyObjects 1.0    

Window {
    visible: true
    width: 360
    height: 360

    MyObject {
        anchors.fill: parent
    }
}

【讨论】:

  • 谢谢,很遗憾这不是我想要的。我知道这种方法,但在我的情况下,我需要调用原始 OpenGL(我正在与应该在该项目上绘制的外部库集成)。我正在尝试做的事情应该是可能的——我在问题中提到的例子也可以做到(场景图 - 渲染 FBO)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多