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



我在QML中看到了一个贝塞尔曲线的示例实现,但我正在寻找如何实现虚线或虚线贝塞尔曲线的提示。据我所见,Bezier曲线示例的作者使用QSGGeometryNode存储在QSGGeometry内部,并在其上应用QSGFlatColorMaterial材料。然后他们只需创建点列表并在点之间绘制线段。

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

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

更新

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

如果不可能,我将使用QPainter

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

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

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

编辑:正如您的更新所示,您错过了我所说的QPainter可以在软件和GL中绘制的部分,GL绘制通常要快得多。此外,通过绘制到GL上下文,您不必将帧缓冲区从CPU移动到GPU内存,它会保存在GPU内存中。所以没有开销。至于动画和其他东西,当然,QPainter不可能让你局限于QPen提供的任何东西——不同的连接、帽等可以在一定程度上用来修改形状,但没有奇迹。。。着色器也不可能实现,只有自定义几何体才能实现。如果你为每个破折号/点元素使用一个基于QObject的对象来独立地设置它们的动画,那么它最终会非常昂贵,QObject非常重,不应该与这样轻的手一起使用。因此,如果你想要这种灵活性,定制总账渲染到FBO是一种很好的方式,但你必须完全脱离QtQuick API,进入总账领域。

无论如何,虚线着色器不应该那么复杂,基本上是根据与曲线的距离和沿其长度的"周期"为片段着色。我发现了这个例子,我自己还没有尝试过。你可以设置阈值的动画,甚至可以使用正弦函数来获得时髦的造型。

至于"纯粹"的QtQuick实现,API并没有真正设计用于处理此类绘图任务,这就是为什么提供Canvas元素来填补空白,并从QML/JS获得高级绘图功能。画布实际上是QPainter的一个包装,它可以绘制FBO。

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

在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 }
    }
}

为什么不使用这种方法:

贝塞尔曲线示例修改为使用QSGVertexColorMaterial

然后,你可以为每个vetex指定你的颜色和字母,以获得破折号、点或你选择的任何图案。

以下是重要部分:

 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);

否,不能在一个几何体节点中存储多个几何体。API对此非常明确。没有理由在那里存储多个几何图形,因为一个节点将一个几何图形和一种材料配对。您可以在节点之间重用几何图形和材质——事实上,这就是它的使用方式。

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

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

一旦为连续笔划项目获得了完整的镶嵌几何体,就可以根据线样式进一步切割它,或者使用着色器。它需要分析来表明线条样式着色器本身就是一个巨大的胜利。很可能你需要一个几何着色器来进行笔划等操作,所有的性能增益都会集中在那里。考虑到要进行的计算数量,线条样式相对简单。

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";
    }
    }
}

最新更新