在QML中绘制虚线和点线贝塞尔曲线

时间:2013-08-20 02:23:09

标签: c++ qt opengl shader qml

我已经看到有a Bezier curve in QML的示例实现,但我正在寻找如何实现虚线或点状贝塞尔曲线的提示。据我所知,Bezier曲线示例的作者使用QSGGeometryNode来存储QSGGeometry内部,并在其上应用了QSGFlatColorMaterial素材。然后他们只需创建点列表并在它们之间绘制段。

是否可以撰写shader并将其应用于QSGFlatColorMaterial(以dasheddotted等方式显示行?)

最终,是否可以在QSGGeometry内存储多个QSGGeometryNode

更新

我想在“纯QtQuick”中实现这一点 - 而不是在“旧”接口(如QPainter etc)中 - 因为我不想使用某些东西,它会切换上下文(openGL和CPU) )。我更喜欢使用自定义着色器的解决方案(如果它可行) - 因为我将有更多的可能性来实现自定义外观(虚线,溺爱,彩色,可能是动画等)。

如果不可能,我会使用QPainter

5 个答案:

答案 0 :(得分:5)

我认为此任务不适合使用QSGGeometryNode实现,使用基于QPainter的绘图和QQuickPaintedItem实现它会更容易。您仍将获得OpenGL的好处,因为QPainter也支持GL绘图,它仍然比软件更快。您可以使用带有点线或虚线图案的股票QPen,也可以使用简单的QVector制作您自己的股票。

或者,您可以使用自定义GL绘图方法,而不是使用Qt提供的类,这些类在表示高级复合几何时非常有限。您甚至可以使用实例化(如果可用)来进一步提高性能,只需沿路径曲线定位破折号或点几何。

最后但并非最不重要的是,您可以使用QML Canvas元素,该元素支持与QPainter几乎相同的操作,并且可能提供相同的性能。

编辑:正如您的更新建议的那样,您错过了我所说的QPainter可以在软件和GL中绘制的部分,而GL绘图通常要快得多。此外,通过绘制到GL上下文,您不必将帧缓冲区从CPU移动到GPU内存,而是将其保存在GPU内存中。所以没有开销。至于动画和其他内容,当然,QPainter不可能限制QPen提供的任何内容 - 不同的连接,大写等可以用来在某种程度上修改形状,但没有奇迹......对于着色器也是不可能的,只有自定义几何体才能实现。如果你为每个短划线/点元素使用一个基于QObject的对象,以便独立地为它们设置动画,那么它最终会非常昂贵,QObject非常重,不应该用这么轻的手。因此,如果您想要这种灵活性,那么定制GL渲染到FBO几乎是可行的方法,但您必须完全从QtQuick API移出并进入GL土地。

无论如何,虚线着色器不应该是那么复杂,基本上你根据曲线的距离和沿着它的长度的“周期”为片段着色。我发现this example,我自己没试过。您可以为阈值设置动画,甚至使用正弦函数来获得时髦的样式。

对于“纯粹的”QtQuick实现,API并没有真正设计用于处理这种类型的绘图任务,这就是为什么提供Canvas元素来填补空白并从QML / JS获得高级痛苦功能的原因。 Canvas实际上是QPainter的包装器,可以吸引FBO。

最后,它不会归结为可能/不可能但是哪种方法最有意义,并且最有效地完成工作。首先尝试QQuickPaintedItem方法,因为它是最简单的方法,如果您对性能不满意,可以针对第一个实现另一个更复杂的解决方案和配置文件。毕竟,这就是为什么QQuickPaintedItem首先被引入的原因 - 处理对QQuickItem类不方便的遗留绘画。

答案 1 :(得分:2)

使用Qt 5.10,已经引入了Shape元素,并且它似乎完全符合您的要求。

https://doc.qt.io/qt-5.10/qml-qtquick-shapes-shape.html

Shape {
    width: 20
    ShapePath {
        strokeColor: "blue"
        strokeWidth: 2
        strokeStyle: ShapePath.DashLine
        startX: 0
        startY: 0
        PathLine { x: parent.width; y: 0 }
    }
}

答案 2 :(得分:1)

为什么不使用这种方法:

Beziercurve example modified to use QSGVertexColorMaterial

然后,您可以为每个vetex指定颜色和alpha,以获得您选择的破折号,点或任何模式。

以下是重要部分:

 geometry = new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), m_segmentCount);
 //geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), m_segmentCount);

QSGVertexColorMaterial *material = new QSGVertexColorMaterial;
//material->setColor(QColor(255, 0, 0));

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

vertices[i].set(x, y, 0, 0, 0, 0);
//vertices[i].set(x, y);

答案 3 :(得分:0)

不,您无法在几何节点中存储多个几何。 API非常明确。没有理由在那里存储多个几何,因为节点将几何和材料配对。您可以在节点之间重用几何和材料 - 实际上就是它的使用方式。

问题的其余部分并不完整,即使提供了基于着色器的实现,它最初也不会非常有用。这只是一个不成熟的优化。让我们来看看你错过了什么。

示例BezierCurve项目只是一个概念证明。它本身并没有用,因为你需要一种方法来链接使用相同笔抚摸的多个项目。你需要类似于简单QPainterPath的东西。事实上,几何本身可以由QPainterPathQPainterPathStroker生成。

一旦您为连续描边的项目获得完整的细分几何体,您可以根据线条样式进一步剪切它,或使用着色器。它需要分析才能显示线条样式着色器本身就是一个巨大的胜利。很可能你需要一个几何着色器来进行抚摸等,所有的性能增益都会集中在那里。想想要完成的计算次数,线条样式相对简单。

答案 4 :(得分:-1)

import QtQuick 2.0

Rectangle {
    width : 1024
    height: 600

    Rectangle {
        x: -3 + 158
        y: 355
        width: 4; height: 4;
        color: "black";
        }

    Rectangle {
        x: 359 + 158
        y: 220
        width: 4; height: 4;
        color: "black";
        }

    Rectangle {
        x: 175 + 158
        y: 238
        width: 2; height: 2;
        color: "black";
        }

    Rectangle {
        x: 711 + 158
        y: 355
        width: 4; height: 4;
        color: "black";
        }

    Rectangle {
        x: 533 + 158
        y: 238
        width: 2; height: 2;
        color: "black";
        }

    Rectangle {
        x: -3 + 118
        y: 355
        width: 4; height: 4;
        color: "darkBlue";
        }

    Rectangle {
        x: 399 + 118
        y: 220
        width: 4; height: 4;
        color: "darkBlue";
        }

    Rectangle {
        x: 196 + 118
        y: 238
        width: 4; height: 4;
        color: "darkBlue";
        }

    Rectangle {
        x: 791 + 118
        y: 355
        width: 4; height: 4;
        color: "darkBlue";
        }

    Rectangle {
        x: 592 + 118
        y: 238
        width: 4; height: 4;
        color: "darkBlue";
        }


    Path {
        id: path
        startX: -3
        startY: 355
        PathQuad { x: 359; y:220; controlX: 175; controlY:238 }
        PathQuad { x: 711; y:355; controlX: 533; controlY:238 }
    }

    Path {
        id: path2
        startX: -3
        startY: 355

        PathQuad { x: 399; y:220; controlX: 196; controlY:238 }
        PathQuad { x: 791; y:355; controlX: 592; controlY:238 }
    }


    PathView {
    id: pathView;
    x: 158
    width: 708
    model: 300;
    path: path
    delegate: Rectangle {
    id: dot;
    width: 1; height: 1;
    color: "red";
    }
    }

    PathView {
    id: pathView2;
    x: 118
    width: 788
    model: 300;
    path: path2
    delegate: Rectangle {
    id: dot2;
    width: 1; height: 1;
    color: "green";
    }
    }
}