Нарисуйте пунктирную и пунктирную кривую Безье в QML
я видел, что есть пример реализации кривая Безье в QML, но я ищу подсказку, как реализовать пунктирную или пунктирную кривую Безье. Насколько я вижу, авторы примера кривой Безье используют QSGGeometryNode
хранить внутри QSGGeometry
С QSGFlatColorMaterial
материал применяется на нем. Затем они просто создают список точек и рисуют сегменты между ними.
можно писать shader
и применить его к QSGFlatColorMaterial
(отображать строке dashed
, dotted
, etc)?
В конце концов, можно ли хранить более одного QSGGeometry
внутри QSGGeometryNode
?
обновление
я хотел бы реализовать это в "чистом QtQuick
" - не в" старых " интерфейсах (например,QPainter etc
) - потому что я не хочу использовать что-то, что переключает контекст (openGL и CPU). Я предпочитаю решение с пользовательским шейдером ( если это выполнимо) - потому что у меня будет больше возможностей в реализации пользовательского внешнего вида (пунктир, doted, цветной, может быть, анимированный и т. д.).
если это невозможно, я буду использовать QPainter
.
5 ответов
я не думаю, что эта задача является хорошим кандидатом для реализации, используя QSGGeometryNode
, было бы намного проще реализовать его с помощью QPainter
основанный чертеж и QQuickPaintedItem
. Вы все равно получите преимущества OpenGL, так как QPainter
поддерживает чертеж ГЛ также и оно все еще быстре чем программное обеспечение. Вы можете использовать запас QPen
С запасом пунктирными или пунктирными узорами или сделайте свой собственный с помощью простого QVector
.
альтернативно, вы можете пойти на пользовательский подход к чертежу GL вместо используя классы Qt, которые довольно ограничены, когда дело доходит до представления передовых геометрии соединения. Вы даже можете использовать экземпляр (если он доступен), чтобы еще больше повысить производительность, и просто расположить тире или точечную геометрию вдоль кривой пути.
и последнее, но не менее важное: вы можете использовать элемент холста QML, который поддерживает почти те же операции, что и QPainter
и, вероятно, предлагает ту же производительность.
EDIT: как следует из вашего обновления, вы пропустили часть, где я сказал QPainter
смогите нарисовать как в програмном обеспечении, так и в GL, при GL рисуя часто значительно более быстро. Кроме того, при рисовании в контексте GL вам не нужно перемещать фреймбуфер из CPU в память GPU, он хранится в памяти GPU. Так что никаких накладных расходов. Что касается анимации и других вещей, конечно, это невозможно с QPainter
вы ограничены тем, что QPen
обеспечивает-различные соединения, крышки и так далее можно использовать для того чтобы доработать форму в некоторой степени, но никакие чудеса... Не получится с шейдерами тоже, это будет возможно только с нестандартной геометрией. И если вы используете QObject
на основе объекта для каждого элемента тире / точки, чтобы независимо анимировать их, он будет в конечном итоге довольно дорогостоящим,QObject
очень тяжелый и не должен использоваться с такой легкой рукой. Таким образом, пользовательский рендеринг GL в FBO-это в значительной степени способ пойти, если вы хотите такую гибкость, но вам придется полностью выйти из API QtQuick и перейти в GL land.
во всяком случае, пунктирная линия шейдер не должен быть таким сложным, в основном вы окрашиваете фрагмент на основе расстояния от кривой и" периода " по ее длине. Я нашел , не пробовал. Вы можете анимировать пороги, даже использовать функцию синуса, чтобы получить фанк-стиль.
Что касается" чистой " реализации QtQuick, API на самом деле не был разработан для обработки такого типа задач рисования, поэтому элемент Canvas был предоставлен для заполнения пробела и получите расширенную функциональность боли от QML / JS. Холст фактически является оберткой вокруг QPainter
это обращается на FBO.
в конце концов, это не сводится к тому, что возможно/невозможно, но какой подход имеет наибольший смысл и наиболее эффективен при выполнении работы. Попробуйте QQuickPaintedItem
подход во-первых, так как это самый простой, если вы не довольны производительностью, вы можете реализовать другое более сложное решение и профиль против первого. Ведь именно поэтому QQuickPaintedItem
был введен в первую очередь-для обработки унаследованной живописи, что не удобно делать с QQuickItem
класса.
Почему бы вам не использовать этот подход:
пример Beziercurve изменен для использования 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);
С 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 }
}
}
нет, вы не можете хранить несколько геометрий в узле геометрии. API очень ясно об этом. Там нет причин хранить несколько геометрий, так как узел соединяет геометрию и материал. Вы можете повторно использовать геометрию и материалы между узлами - именно так она и предназначена для использования.
остальная часть вопроса на самом деле не завершена, и даже если была предоставлена реализация на основе шейдеров, она не будет очень полезной изначально. Это будет просто преждевременно оптимизация. Давайте посмотрим, что вы пропали.
пример элемента BezierCurve-это просто доказательство концепции. Это не полезно само по себе, так как вам нужен способ цепочки нескольких элементов, которые гладятся с помощью одного и того же пера. Вам нужно что-то сродни простому QPainterPath
. Фактически, сама геометрия может быть порождена QPainterPath
и QPainterPathStroker
.
после того как вы получили полный мозаично геометрии для непрерывно-погладил элемент, вы можете либо далее ее порезать на основе стиля линии или использования шейдера. Потребуется профилирование, чтобы показать, что шейдер в стиле линии сам по себе является большой победой. Вполне может быть, что вам нужен геометрический шейдер для поглаживания и т. д. и весь прирост производительности будет сосредоточен там. Подумайте о количестве вычислений, которые нужно сделать, стиль линии относительно прост.
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";
}
}
}