我已经看到有a Bezier curve in QML的示例实现,但我正在寻找如何实现虚线或点状贝塞尔曲线的提示。据我所知,Bezier曲线示例的作者使用QSGGeometryNode
来存储QSGGeometry
内部,并在其上应用了QSGFlatColorMaterial
素材。然后他们只需创建点列表并在它们之间绘制段。
是否可以撰写shader
并将其应用于QSGFlatColorMaterial
(以dashed
,dotted
等方式显示行?)
最终,是否可以在QSGGeometry
内存储多个QSGGeometryNode
?
更新
我想在“纯QtQuick
”中实现这一点 - 而不是在“旧”接口(如QPainter etc
)中 - 因为我不想使用某些东西,它会切换上下文(openGL和CPU) )。我更喜欢使用自定义着色器的解决方案(如果它可行) - 因为我将有更多的可能性来实现自定义外观(虚线,溺爱,彩色,可能是动画等)。
如果不可能,我会使用QPainter
。
答案 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
的东西。事实上,几何本身可以由QPainterPath
和QPainterPathStroker
生成。
一旦您为连续描边的项目获得完整的细分几何体,您可以根据线条样式进一步剪切它,或使用着色器。它需要分析才能显示线条样式着色器本身就是一个巨大的胜利。很可能你需要一个几何着色器来进行抚摸等,所有的性能增益都会集中在那里。想想要完成的计算次数,线条样式相对简单。
答案 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";
}
}
}