QT场景图无法绘制网格

时间:2018-09-12 05:33:19

标签: qt opengl qml rendering scenegraph

我想使用Qt场景图绘制网格。我有几天没有研究成功。请帮助我,谢谢!

问题是:

  1. 为什么我不能显示结果?
  2. 我在哪里称glViewport?或其他方式?

我遵循了代码,发现Qt在renderer->setViewportRect(rect)中调用了QQuickWindowPrivate::renderSceneGraph()

但是场景图使用整个窗口而不是自定义QQuickItem对象作为绘制区域。

我重新计算了着色器矩阵,但是没有用。我觉得这很丑

source code

// grid_item.h
class GridItem : public QQuickItem
{
    Q_OBJECT

public:
    explicit GridItem(QQuickItem *parent = nullptr);

protected:
    QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) Q_DECL_OVERRIDE;
};

// grid_item.cpp
GridItem::GridItem(QQuickItem *parent) : QQuickItem (parent)
{
    setFlag(ItemHasContents, true);
}

QSGNode *GridItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{
    QRectF rect = boundingRect();

    if (rect.isEmpty()) {
        delete oldNode;
        return nullptr;
    }

    QSGGeometryNode *node = nullptr;
    QSGGeometry *geometry = nullptr;
    GridItemMaterial *material = nullptr;

    if(!oldNode)
    {
        node = new QSGGeometryNode;
        node->setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial, true);

        geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 0);
        geometry->setDrawingMode(QSGGeometry::DrawLines);
        node->setGeometry(geometry);

        material = new GridItemMaterial;
        material->setFlag(QSGMaterial::RequiresDeterminant, true);
        node->setMaterial(material);
    }
    else
    {
        node = static_cast<QSGGeometryNode *>(oldNode);
        geometry = node->geometry();
        material = static_cast<GridItemMaterial *>(node->material());
    }

    int m_xAxisSegment {10};
    int m_yAxisSegment {10};
    const int totalVertices = (m_xAxisSegment+1)*2 + (m_yAxisSegment+1)*2;

    if(geometry->vertexCount() != totalVertices)
    {
        geometry->allocate(totalVertices);

        QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D();

        for(int x=0; x<=m_xAxisSegment; x++)
        {
            float xPos = 1.0f*x/m_xAxisSegment;

            (*vertices++).set(xPos, 0.0f);
            (*vertices++).set(xPos, 1.0f);
        }

        for(int y=0; y<=m_yAxisSegment; y++)
        {
            float yPos = 1.0f*y/m_yAxisSegment;

            (*vertices++).set(0.0f, yPos);
            (*vertices++).set(1.0f, yPos);
        }

        node->markDirty(QSGNode::DirtyGeometry);
    }

    // calculate matrix for shader
    ConvertParameter param;
    param.windowWidth = 640;
    param.windowHeight = 480;

    param.contentX = 100;
    param.contentY = 100;
    param.contentWidth = 200;
    param.contentHeight = 200;

    param.glX = 0;
    param.glY = 0;
    param.glWidth = 1.0f;
    param.glHeight = 1.0f;

    material->m_convertParameter = param;

    return node;
}

// grid_item_material.h
class GridItemMaterial : public QSGMaterial
{
public:
    QSGMaterialType *type() const Q_DECL_OVERRIDE;
    QSGMaterialShader *createShader() const Q_DECL_OVERRIDE;

    ConvertParameter m_convertParameter;
};

// grid_item_material.cpp
QSGMaterialType *GridItemMaterial::type() const
{
    static QSGMaterialType type;
    return &type;
}

QSGMaterialShader *GridItemMaterial::createShader() const
{
    return new GridItemMaterialShader;
}

// grid_item_material_shader.h
class GridItemMaterialShader : public QSGMaterialShader
{
public:
    GridItemMaterialShader();

    const char *const *attributeNames() const Q_DECL_OVERRIDE;
    void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) Q_DECL_OVERRIDE;

protected:
    void initialize() Q_DECL_OVERRIDE;

    QMatrix4x4 getConvertMatrix(const ConvertParameter &param);

private:
    int m_id_mvpMatrix {-1};
    int m_id_gridlineColor {-1};
};

// grid_item_material_shader.cpp
GridItemMaterialShader::GridItemMaterialShader()
{
    setShaderSourceFile(QOpenGLShader::Vertex, ":/shaders/gridlines.vert");
    setShaderSourceFile(QOpenGLShader::Fragment, ":/shaders/gridlines.frag");
}

const char * const *GridItemMaterialShader::attributeNames() const
{
    static char const *const names[] = { "Vertex", 0 };
    return names;
}

void GridItemMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *)
{
    GridItemMaterial *material = static_cast<GridItemMaterial *>(newMaterial);

    QMatrix4x4 matrix = getConvertMatrix(material->m_convertParameter);
    program()->setUniformValue(m_id_mvpMatrix, matrix);

    program()->setUniformValue(m_id_gridlineColor, QColor::fromRgbF(1, 0, 0, 1));
}

void GridItemMaterialShader::initialize()
{
    m_id_mvpMatrix = program()->uniformLocation("mvpMatrix");
    m_id_gridlineColor = program()->uniformLocation("gridlineColor");
}

QMatrix4x4 GridItemMaterialShader::getConvertMatrix(const ConvertParameter &param)
{
    QMatrix4x4 model1;

    // convert window to (-1, -1)..(+1, +1)
    model1.setToIdentity();
    model1.translate(-1, -1, 0);
    model1.scale(2.0f/param.windowWidth, 2.0f/param.windowHeight, 1.0f);

    // left-bottom
    QVector4D v3(param.contentX, param.windowHeight-param.contentY-param.contentHeight, 0, 1);
    v3 = model1 * v3;

    // right-top
    QVector4D v4(param.contentX+param.contentWidth, param.windowHeight-param.contentY, 0, 1);
    v4 = model1 * v4;

    // content area should in (-1, -1)..(+1, +1)
    float width = v4.x() - v3.x();
    float height = v4.y() - v3.y();

    QMatrix4x4 model2;
    model2.setToIdentity();
    model2.translate(v3.x(), v3.y(), 0);
    model2.scale(width/param.glWidth, height/param.glHeight, 1);
    model2.translate(-param.glX, -param.glY, 0);

    return model2;
}

// grid_convert_parameter.h
struct ConvertParameter
{
    int windowWidth = 640;
    int windowHeight = 480;

    int contentX = 100;
    int contentY = 100;
    int contentWidth = 200;
    int contentHeight = 200;

    float glX = 3;
    float glY = 3;
    float glWidth = 4.0f;
    float glHeight = 4.0f;
};

// main.cpp
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<GridItem>("io.draw", 1, 0, "GridItem");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    QQuickWindow *window = static_cast<QQuickWindow *>(engine.rootObjects().first());

    QSurfaceFormat format = window->requestedFormat();
    format.setProfile(QSurfaceFormat::CoreProfile);
    format.setVersion(3, 3);
    window->setFormat(format);

    window->show();

    return app.exec();
}

// main.qml
import QtQuick 2.9
import QtQuick.Controls 2.4
import io.draw 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    GridItem {
        x: 100
        y: 100
        width: 200
        height: 200
    }
}

// gridlines.vert
#version 330 core

uniform mat4 mvpMatrix;

layout(location = 0) in vec2 Vertex;

void main(void)
{
    gl_Position = mvpMatrix * vec4(Vertex, 0.0, 1.0);
}

// gridlines.frag
#version 330 core

uniform vec4 gridlineColor;

layout(location = 0) out vec4 fragColor;

void main(void)
{
    fragColor = gridlineColor;
}

我还基于Qt OpenGL演示进行了简单的更改。

class OpenGLWindow : public QWindow, protected QOpenGLFunctions_3_3_Core

除了将结果直接输出到整个窗口外,几乎做同样的事情(但这不是我想要的)

另一个区别是变换矩阵已更改:

QMatrix4x4 model, view, projection;
projection.ortho(0, 1, 0, 1, -10, 10);
m_program->setUniformValue(m_matrixUniform, projection*view*model);

它正常工作...

因为它涉及OpenGL和Qt场景图,所以我不知道出了什么问题。

0 个答案:

没有答案