Подтвердить что ты не робот

Нарисуйте пунктирную и пунктирную кривую Безье в QML

Я видел пример реализации кривой Безье в QML, но я ищу подсказку, как реализовать пунктир или пунктирная линия кривой безье. Насколько я вижу, авторы примера кривой Безье используют QSGGeometryNode для хранения внутри QSGGeometry с помощью материала QSGFlatColorMaterial, применяемого к нему. Затем они просто создают список точек и рисуют сегменты между ними.

Можно ли написать shader и применить его к QSGFlatColorMaterial (для отображения строки как dashed, dotted и т.д.)?

В конце концов, можно ли хранить более одного QSGGeometry внутри QSGGeometryNode?

UPDATE

Я хотел бы реализовать это в "pure QtQuick" - не в "старых" интерфейсах (например, QPainter etc)), потому что я не хочу использовать что-то, что переключает контекст (openGL и CPU). Я предпочитаю решение с пользовательским шейдером (если это выполнимо), потому что у меня будет больше возможностей для реализации пользовательского внешнего вида (пунктирная, придуманная, цветная, анимированная и т.д.).

Если это невозможно, я буду использовать QPainter.

4b9b3361

Ответ 1

Я не думаю, что эта задача является хорошим кандидатом для реализации с использованием QSGGeometryNode, было бы намного проще реализовать ее с использованием чертежа QPainter и QQuickPaintedItem. Вы по-прежнему получаете преимущества OpenGL, поскольку QPainter поддерживает также чертеж GL, и он все же быстрее, чем программное обеспечение. Вы можете использовать запас QPen со скопированными пунктирными или пунктирными узорами или сделать свой собственный с помощью простого QVector.

В качестве альтернативы вы можете перейти к пользовательскому подходу GL-рисования вместо использования классов Qt, которые довольно ограничены, когда речь заходит о представлении передовой сложной геометрии. Вы даже можете использовать instancing (если есть), чтобы улучшить производительность еще больше, и просто поместите тире или точную геометрию вдоль кривой пути.

И последнее, но не менее важное: вы можете использовать элемент QML Canvas, который поддерживает почти те же операции, что и QPainter, и, вероятно, предлагает ту же производительность.

РЕДАКТИРОВАТЬ: Как показывает ваше обновление, вы пропустили ту часть, в которой я сказал, что QPainter может рисовать как в программном обеспечении, так и в GL, при этом GL-рисунок часто значительно быстрее. Кроме того, при рисовании в контексте GL вам не нужно перемещать фреймбуфер из CPU в память GPU, он хранится в памяти графического процессора. Так что никаких накладных расходов. Что касается анимаций и других вещей, конечно, это невозможно с QPainter, вы ограничены тем, что QPen обеспечивает - различные объединения, кепки и т.д. Можно использовать для изменения формы до некоторой степени, но не чудес... Это тоже будет невозможно с шейдерами, это возможно только с пользовательской геометрией. И если вы используете объект QObject для каждого элемента штриховки/точки для того, чтобы независимо анимировать их, он будет довольно дорогостоящим, QObject очень тяжелым и не должен использоваться с такой легкой рукой. Таким образом, настраиваемый GL-рендеринг для FBO - это в значительной степени способ, если вы хотите такую ​​гибкость, но вам придется полностью отказаться от API QtQuick и в землю GL.

Во всяком случае, штриховой линейный шейдер не должен быть таким сложным, в основном вы окрашиваете фрагмент на основе расстояния от кривой и "периода" вдоль его длины. Я нашел этот пример, сам не пробовал. Вы можете анимировать пороги, даже использовать синусоидальную функцию, чтобы получить фанки выглядящий стиль.

Что касается "чистой" реализации QtQuick, API на самом деле не был предназначен для обработки таких задач рисования, поэтому элемент Canvas был предоставлен для заполнения пробела и получения расширенной функциональности для обработки из QML/JS. Canvas фактически является оберткой вокруг QPainter, которая рисует FBO.

В конце концов, это не сводится к тому, что возможно/невозможно, но какой подход имеет наибольший смысл и наиболее эффективен при выполнении работы. Сначала попробуйте подход QQuickPaintedItem, так как он является самым легким, если вас не устраивает производительность, вы можете реализовать еще одно более сложное решение и профиль для первого. В конце концов, именно поэтому QQuickPaintedItem был введен в первую очередь - обрабатывать устаревшую картину, что не удобно делать с классом QQuickItem.

Ответ 2

Почему бы вам не использовать этот подход:

Пример 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);

Ответ 3

Нет, вы не можете хранить несколько геометрий в геометрии node. API очень откровенен в этом. Там нет оснований хранить несколько геометрий там, поскольку node соединяет геометрию и материал. Вы можете повторно использовать геометрию и материалы между узлами - то, как оно предназначено для использования, на самом деле.

Остальная часть вопроса не совсем завершена, и даже если бы была реализована реализация на основе шейдеров, сначала это будет не очень полезно. Это будет преждевременная оптимизация. Давайте посмотрим, что вам не хватает.

Пример "Безье" - это просто доказательство концепции. Это не полезно само по себе, так как вам нужен способ связывания нескольких элементов, которые гладят с помощью одного и того же пера. Вам нужно что-то похожее на простой QPainterPath. Фактически, сама геометрия могла быть сгенерирована с помощью QPainterPath и QPainterPathStroker.

После того, как у вас есть полная тесселированная геометрия для объекта с непрерывным поглаживанием, вы можете либо отрезать его по стилю линии, либо использовать шейдер. Это потребует профилирования, чтобы показать, что линейный шейдер сам по себе является большой победой. Вполне возможно, что вам нужен геометрический шейдер для выполнения поглаживания и т.д., И все усиление производительности будет сосредоточено там. Подумайте о количестве вычислений, которые необходимо выполнить, стиль линии относительно прост.

Ответ 4

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