2013-08-20 7 views
13

Widziałem przykład implementacji a Bezier curve in QML, ale szukam podpowiedzi, jak zaimplementować przerywaną lub przerywaną linię krzywej Beziera. O ile widzę, autorzy przykładu krzywej Beziera używają QSGGeometryNode do przechowywania wewnątrz QSGGeometry z nałożonym na niego materiałem QSGFlatColorMaterial. Następnie po prostu tworzą listę punktów i rysują między nimi segmenty.Narysuj przerywaną i kropkowaną krzywą Beziera w QML

Czy można napisać i zastosować go do QSGFlatColorMaterial (aby wyświetlić linię jako dashed, dotted itd.)?

Ostatecznie możliwe jest zapisanie więcej niż jednego QSGGeometry wewnątrz QSGGeometryNode?

UPDATE

chciałbym zaimplementować to w "czystej QtQuick" - nie w "starych" interfejsów (np QPainter etc) - bo nie chcę użyć czegoś, co spowoduje przełączenie kontekstu (OpenGL i CPU). Preferuję rozwiązanie z niestandardowym shaderem (jeśli jest to wykonalne) - ponieważ będę miał więcej możliwości w zakresie niestandardowego wyglądu i stylu (przerywana, zapadająca w pamięć, kolorowa, może animowana itp.).

Jeśli nie jest to możliwe, użyję QPainter.

+0

I t jest względnie trywialne, aby zmienić przykład krzywej Beziera w celu wygenerowania geometrii dla każdego z podsegmentów w zależności od potrzeb w wybranym stylu linii. –

Odpowiedz

5

Nie sądzę, że to zadanie jest dobrym kandydatem do implementacji przy użyciu QSGGeometryNode, znacznie łatwiej byłoby go wdrożyć przy użyciu rysunku opartego na QPainter i QQuickPaintedItem. Nadal będziesz czerpał korzyści z OpenGL, ponieważ QPainter obsługuje również rysowanie GL i wciąż jest szybsze niż oprogramowanie. Możesz użyć zapasów QPen z deseniami przerywanymi lub przerywanymi, lub zrób własne z prostym QVector.

Zamiast tego można zastosować niestandardowe podejście do rysowania GL zamiast klas dostarczonych przez Qt, które są dość ograniczone, jeśli chodzi o reprezentowanie zaawansowanej geometrii złożonej. Możesz nawet użyć instancji (jeśli jest dostępna), aby jeszcze bardziej poprawić wydajność i po prostu ustawić kreski lub geometrię punktów wzdłuż krzywej ścieżki.

Wreszcie można użyć elementu Canvas QML, który obsługuje prawie takie same operacje, jak QPainter i prawdopodobnie oferuje taką samą wydajność.

EDYCJA: Jak sugeruje twoja aktualizacja, przegapiłeś część, w której powiedziałem, że QPainter może narysować zarówno oprogramowanie, jak i GL, przy czym rysunek GL jest często znacznie szybszy. Ponadto, rysując do kontekstu GL, nie musisz przenosić bufora ramki z CPU do pamięci GPU, jest on przechowywany w pamięci GPU. Więc nie ma narzutów. Jeśli chodzi o animacje i inne rzeczy, z pewnością nie jest to możliwe z QPainter jesteś ograniczony do tego, co zapewnia QPen - różne połączenia, czapki i tak dalej mogą być użyte do modyfikacji kształtu w pewnym stopniu, ale bez cudów ... Wygrało W przypadku shaderów nie będzie to możliwe, będzie to możliwe tylko w przypadku niestandardowej geometrii. A jeśli użyjesz obiektu opartego na QObject dla każdego elementu myślnik/kropka, aby je niezależnie ożywić, skończy się to całkiem kosztownie, QObject jest bardzo ciężki i nie powinien być używany z tak lekką ręką. Więc niestandardowe renderowanie GL do FBO jest prawie do zrobienia, jeśli chcesz tego rodzaju elastyczność, ale będziesz musiał całkowicie przenieść się z API QtQuick i do lądowania GL.

W każdym razie, linijka przerywana nie powinna być tak skomplikowana, właściwie kolorujemy fragment na podstawie odległości od krzywej i "kropki" na całej długości. Znalazłem this example, nie próbowałem go samodzielnie.Możesz animować progi, a nawet korzystać z funkcji sinusoidalnej, aby uzyskać stylowy wygląd.

Jeśli chodzi o "czystą" implementację QtQuick, interfejs API tak naprawdę nie został zaprojektowany do obsługi tego rodzaju zadań rysunkowych, dlatego element Canvas został wprowadzony w celu wypełnienia luki i uzyskania zaawansowanej funkcji malowania z poziomu QML/JS. Płótno jest w rzeczywistości opakowaniem o numerze QPainter, które jest wczytywane do pliku FBO.

Ostatecznie nie sprowadza się do tego, co jest możliwe/niemożliwe, ale które podejście jest najbardziej sensowne i najskuteczniejsze w wykonaniu pracy. Wypróbuj najpierw podejście QQuickPaintedItem, ponieważ jest to najłatwiejsze, jeśli nie jesteś zadowolony z wydajności, możesz zaimplementować inne, bardziej złożone rozwiązanie i profil względem pierwszego. Wszakże dlatego wprowadzono po prostu QQuickPaintedItem - aby obsłużyć stare malarstwo, które nie jest wygodne dla klasy QQuickItem.

+2

Dziękuję bardzo, ale chciałbym wprowadzić to w czystym 'QtQuick' - nie chciałbym używać' QPaintera' - jeśli to możliwe. Jeśli nie, użyję go - zobacz zaktualizowane pytanie. Gdyby można było napisać moduł cieniujący, byłby on o wiele bardziej wydajny niż użycie predefiniowanych stylów 'QPainter'. –

+0

Jest to nadal czysta implementacja QtQuick, 'QQuickPaintedItem', jak sugeruje nazwa, jest częścią API QtQuick2. Możesz tworzyć własne wzorce stylów dla 'QPainter' bardzo łatwo. Zastanawiam się również nad wieloma geometriami, ale wygląda na to, że API nie jest w stanie tego zrobić. Ostatecznie jest to 'QPainter' lub własne renderowanie do framebuffera, które możesz narysować na prostokącie. Przypuszczam, że shader jest możliwy, ale nie jest to najbardziej eleganckie rozwiązanie tego problemu. Możesz spojrzeć na kod 'QPainter', który rysuje w kontekście GL, używa również geometrii do rysowania. – dtech

+0

Dziękujemy za wszystkie wyjaśnienia! Próbuję wykonać to zadanie za pomocą modułu cieniującego, ponieważ chcę go animować i łatwiej byłoby zrobić to za pomocą shaderów. Znam podstawy shaderów OGL, więc nie będę miał problemu z napisaniem tego. Jedynym problemem jest jak go używać z 'QSGFlatColorMaterial' w' QML' - Spróbuję znaleźć sposób, ale jeśli go znasz, byłbym wdzięczny za podpowiedź :) –

0

Nie, nie można przechowywać wielu geometrii w węźle geometrii. Interfejs API jest bardzo wyraźny. Nie ma powodu, aby przechowywać tam wiele geometrii, ponieważ węzeł paruje geometrię i materiał. Możesz ponownie użyć geometrii i materiałów między węzłami - tak właśnie ma być używana.

Reszta pytania nie jest kompletna, a nawet jeśli zapewniono implementację opartą na cieniowaniu, początkowo nie będzie ona zbyt użyteczna. To będzie tylko przedwczesna optymalizacja. Spójrzmy na to, czego brakuje.

Przykładowy element BezierCurve to tylko dowód koncepcji. Sam nie jest przydatny, ponieważ potrzebujesz sposobu na łańcuchy wielu elementów, które są głaskane przy użyciu tego samego pióra. Potrzebujesz czegoś podobnego do prostego QPainterPath. W rzeczywistości sama geometria może być generowana przez QPainterPath i QPainterPathStroker.

Po uzyskaniu kompletnej geometrii tesselowanej dla elementu o ciągłym głaskaniu można go następnie obcinać w oparciu o styl linii lub użyć modułu cieniującego. Wymagałoby to profilowania, aby pokazać, że sam shader w stylu linii jest wielką wygraną. Może się okazać, że potrzebujesz shaderów geometrii, aby wykonać głaskanie itd., A cały przyrost wydajności zostanie tam wyśrodkowany. Pomyśl o liczbie obliczeń do wykonania, stylizacja linii jest stosunkowo prosta.

+0

Dziękuję. Czy masz jakiś przykład, który używa zarówno - 'QML' i shaderów? Całkowicie rozumiem twoją odpowiedź, ale jestem nowy w QML, więc prosty przykład może mi bardzo pomóc. –

+0

Tutaj masz: http://qt-project.org/doc/qt-5.1/qtquick/shadereffects.html – dtech

1

Dlaczego nie można korzystać z tego podejścia:

Beziercurve example modified to use QSGVertexColorMaterial

Następnie można określić kolor i alfa dla każdego vetex, aby uzyskać kreski, kropki, czy cokolwiek wzór wybrać.

Oto ważne elementy:

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