2009-03-26 9 views
19

Mam ścieżkę złożoną z listy punktów 2D. Chcę zamienić je w pasek trójkątów, aby utworzyć teksturowaną linię o określonej grubości (i inne tego typu rzeczy). Zasadniczo lista punktów 2D musi stać się listą wierzchołków określających obrys wieloboku, który w przypadku renderowania renderowałby linię. Problem polega na obsłudze połączeń narożnych, miterów, czapek itp. Powstały wielokąt musi być "idealny" w sensie bez nadmiernego przeciągania, czystych połączeń itp., Aby można było go wytłaczać lub w inny sposób bawić się.Jak renderować grube linie 2D jako wielokąty?

Czy istnieją jakieś proste zasoby o wartości , które mogą zapewnić wgląd algorytmu, kod lub dodatkowe informacje na temat robienia tego w wydajny sposób?

Absolutnie NIE chcę pełnej biblioteki wektorowej 2D (cairo, antigrain, OpenVG itp.) Z krzywymi, łukami, kreskami i wszystkimi dzwonkami i gwizdkami. Kopałem w wielu drzewach źródłowych dla implementacji OpenVG i innych rzeczy, aby znaleźć wgląd, ale to wszystko jest okropnie zawiłe.

Zdecydowanie jestem gotów samemu go zakodować, ale istnieje wiele zdegenerowanych przypadków (małe segmenty + grube szerokości + ostre rogi), które tworzą wszelkiego rodzaju problemy z łączeniem. Nawet niewielka pomoc zaoszczędziłaby mi godzin próbując poradzić sobie z nimi wszystkimi.

EDYCJA: Oto przykład jednego z tych zdegenerowanych przypadków, który powoduje brzydotę, jeśli po prostu przechodzisz od wierzchołka do wierzchołka. Czerwony to oryginalna ścieżka. Pomarańczowe bloki to prostokąty rysowane na określonej szerokości wyrównane i wyśrodkowane na każdym segmencie.

http://www.freeimagehosting.net/uploads/52dc639727.png

+0

Ja też tego chcę. Zrobiłem to w prototypie, używając prostych pudełek między punktami, ale ostatecznie trzeba je naprawić. Mam nadzieję, że twoje pytanie przyciąga właściwe odpowiedzi. Tak czy inaczej, wróć do nas i powiedz nam, co ostatecznie zrobiłeś. –

+0

W odpowiedzi na twoje zdjęcie nie przecinasz kątów, przechodzisz prostopadle do linii. –

+0

Tak, wiem. To jest pre-whatever-join-algorithm-gets-applied. Po prostu ilustruję sprawę problemu, a nie to, co dzieje się, gdy faktycznie coś do niej zastosujesz. –

Odpowiedz

4

No cóż - sam próbowałem rozwiązać ten problem. Zmarnowałem dwa miesiące na rozwiązanie, które próbowało rozwiązać problem z nadmiernym przeciążeniem. Jak już się dowiedziałeś, nie możesz zajmować się wszystkimi zdegenerowanymi sprawami i jednocześnie mieć zero overdraw.

Można jednak używać hybrydowego podejścia:

Napisz sobie rutynę, która sprawdza czy przyłącza może być wykonany z prostej geometrii bez problemów. Aby to zrobić, należy sprawdzić kąt łączenia, szerokość linii i długość połączonych segmentów linii (segmenty linii, które są krótsze niż ich szerokość, są PITA). Przy niektórych heurystyce powinieneś być w stanie uporządkować wszystkie trywialne przypadki.

Nie wiem, jak wyglądają twoje średnie dane linii, ale w moim przypadku ponad 90% szerokich linii nie miało zdegenerowanych przypadków.

Dla wszystkich innych liniach:

pan najprawdopodobniej już okazało się, że jeśli tolerować overdraw, generowanie geometrii jest dużo łatwiejsze. Zrób tak, a niech algorytm wieloboków CSG i algorytm tesselacji wykonają ciężką pracę.

Oceniłem większość dostępnych pakietów tesselation, a skończyłem z tesselatorem GLU. Był szybki, niezawodny, niezniszczalny (w przeciwieństwie do większości innych algorytmów). To było darmowe, a licencja pozwoliła mi włączyć go do komercyjnego programu. Jakość i szybkość tesselation jest w porządku. Nie dostaniesz jakości triangulacji delaunay, ale ponieważ potrzebujesz trójkątów do renderowania, który nie jest problemem.

Ponieważ nie podobało mi się to, że interfejs API tesselator podniósł kod tesselation z darmowej implementacji referencyjnej SGI OpenGL, przepisałem całą partycję front-end i dodałem pule pamięci, aby zmniejszyć liczbę alokacji. Trwało to dwa dni, ale było warto (jak poprawa wydajności piątego czynnika). Rozwiązanie znalazło się w komercyjnej implementacji OpenVG btw :-)

Jeśli renderujesz z OpenGL na komputerze PC, możesz przenieść zadanie tesselation/CSG z CPU na GPU i użyć bufora matrycowego lub sztuczki z-bufora, aby usunąć overdraw. To jest o wiele łatwiejsze i może być nawet szybsze niż tesselacja procesora.

+0

co to jest PITA? i co musisz zrobić, gdy szerokość linii jest większa niż długość segmentów linii? – moka

+0

@moka: PITA = Ból w dupie – aehlke

+0

Czym dokładnie są te zdegenerowane przypadki? Nie widzę problemu? – paulm

0

myślę, że dotrzeć do algorytmu teselacji. Prawdą jest, że w większości przypadków, gdy są one używane, celem jest zmniejszenie liczby wierzchołków w celu zoptymalizowania renderowania, ale w twoim przypadku można sparametryzować, aby zachować wszystkie szczegóły - a możliwość optymalizacji może się przydać.

Istnieje wiele algorytmów tesselowania i kodu w Internecie - w parę lat później zawarłem czysty plik DLL w bibliotece DLL do użytku z rendererem krajobrazu Delphi i nie są one rzadkim tematem dla zaawansowanych samouczków kodowania grafiki i tym podobne.

0

Ja też się tym interesuję, ponieważ chcę udoskonalić rysunek dróg z mapowania aplikacji (Kosmos). Jednym z rozwiązań, których używałem, było dwukrotne narysowanie polilinii, jeden raz grubszą linią, a raz cieńszą, z innym kolorem. Ale to nie jest wielobok, to tylko szybki sposób na symulację. Zobacz kilka przykładów tutaj: http://wiki.openstreetmap.org/wiki/Kosmos_Rendering_Help#Rendering_Options

Nie jestem pewien, czy tego właśnie potrzebujesz.

2

Prosta metoda z mojej góry.

Bisect kąt każdego 2d Vertex, to stworzy miłe ukośne linii. Następnie przesuń wzdłuż tej linii, zarówno do wewnątrz, jak i na zewnątrz, ilość twojej "grubości" (lub grubość podzieloną przez dwie?), Teraz masz swoje wewnętrzne i zewnętrzne punkty wielokąta. Przejdź do następnego punktu, powtórz ten sam proces, budując nowe punkty wielokąta po drodze. Następnie zastosuj triangualtion, aby uzyskać gotowe vertexy do renderowania.

+0

Miałem tę część wymyśloną. :) Problem polega na tym, że istnieje kilka przypadków, w których te wierzchołki generowały zachodzące na siebie trójkąty. Zasadniczo potrzebuję wyeliminować wierzchołki, które skończyłyby się powodując dziwne artefakty. –

+0

w jaki sposób zachodzą na siebie? –

+0

Nie sądzę, że rozumiesz część bisekcji. –

0

W moim przypadku mogłem pozwolić sobie na przekroczenie. Ja po prostu drążę koła o promieniu = szerokość/2 wyśrodkowane na każdym z wierzchołków polilinii.

Artefakty są zamaskowane w ten sposób i bardzo łatwe do zrealizowania, jeśli możesz żyć z "zaokrąglonymi" rogami i nadmiarowaniem.

0

Wygląda na to, że rysujesz pole wokół segmentów linii z WYPEŁNIENIEM i używanie koloru pomarańczowego. Czyniąc to, na pewno stworzysz złe overdraws. Pierwszą rzeczą do zrobienia nie będzie renderowanie czarnych obramowań, a kolor wypełnienia może być nieprzejrzysty.

Dlaczego nie możesz użyć prymitywu GL_LINES, aby zrobić to, co masz zamiar zrobić? Możesz określić szerokość, filtrowanie, gładkość, cokolwiek teksturę. Możesz renderować wszystkie wierzchołki za pomocą glDrawArrays(). Wiem, że nie jest to coś, o czym myślisz, ale ponieważ koncentrujesz się na rysunku 2D, może to być łatwiejsze podejście. (szukaj Teksturowanych linii itp.)

1

Skończyło się na tym, że musiałem zabrudzić sobie ręce i napisać małą wstążkę, aby rozwiązać podobny problem.

Dla mnie problemem było to, że chciałem grubych linii w OpenGL, które nie miały rodzajów artefaktów, które widziałem z OpenGL na iPhonie. Po obejrzeniu różnych rozwiązań; Krzywe Beziera i tym podobne - uznałem, że najprościej byłoby po prostu stworzyć własną. Istnieje kilka różnych podejść.

Jednym ze sposobów jest znalezienie kąta przecięcia między dwoma segmentami, a następnie przesuwanie się wzdłuż tej linii przecięcia w pewnej odległości od powierzchni i traktowanie jej jako wierzchołka wstążki. Próbowałem tego i nie wyglądało to intuicyjnie; szerokość wstążki byłaby różna.

Innym podejściem jest faktyczne obliczenie normalnej do powierzchni segmentów linii i wykorzystanie jej do obliczenia idealnej krawędzi taśmy dla tego segmentu i wykonanie rzeczywistych testów przecięcia między segmentami wstążki. To działało dobrze, z wyjątkiem tego, że w przypadku ostrych zakrętów przecięcia segmentów linii wstążkowej były zbyt daleko (jeśli kąt między segmentami zbliżał się do 180 ').

Pracowałem nad kwestią ostrych kątów z dwoma podejściami. Algorytm przecięcia linii Paul Bourke (którego użyłem w sposób niezoptymalizowany) sugerował wykrycie, czy przecięcie znajduje się wewnątrz segmentów. Ponieważ oba segmenty są identyczne, musiałem tylko przetestować jeden z segmentów na skrzyżowanie. Mógłbym wtedy rozstrzygnąć, jak rozwiązać ten problem; albo przez fudowanie najlepszego punktu pomiędzy dwoma końcami, albo przez zakładanie zaślepki - oba podejścia wyglądają dobrze - podejście z nakładką końcową może zrzucić wielokąt przedni/tylny w kolejności zamawiania dla opengl.

Zobacz http://paulbourke.net/geometry/lineline2d/

Zobacz mój kod źródłowy tutaj: https://gist.github.com/1474156

+0

Jednym z moich domowych przesłuchań z PostScriptem i niestety inne paradygmaty rysunku podążają za jego przykładem, jest to, że narożniki ucięte są albo rysowane jako perfekcyjna miter (jeśli nie wykracza poza granicę ścięcia) albo jako faza. Zastanawiam się, dlaczego ten limit nie mógł być użyty jako punkt "odcięcia" kąta pod kątem. – supercat

2

Właśnie znalazłem tę niesamowitą pracę:

http://www.codeproject.com/Articles/226569/Drawing-polylines-by-tessellation

Wydaje zrobić dokładnie to, co chcesz, a jej licencja zezwala używać go nawet w aplikacjach komercyjnych. Poza tym autor wykonał naprawdę świetną robotę, aby szczegółowo opisać swoją metodę. Pewnie dam mu szansę, żeby zastąpić moją własną, prawie niezupełnie idealną implementację.

+0

Podczas gdy ten link może odpowiedzieć na pytanie, lepiej umieścić w nim istotne części odpowiedzi i podać link do odsyłacza. Odpowiedzi dotyczące linków mogą stać się nieprawidłowe, jeśli strona z linkami się zmieni. – AstroCB

+0

@AstroCB: Wystarczająco sprawiedliwe, ale pytanie zadawane przez PO jest w rzeczywistości niezwykle trudnym pytaniem.W rzeczywistości jest to dość otwarty problem badawczy. Nie ma mowy, aby dobra odpowiedź dobrze pasowała do Stack Overlow. Link do całkiem dobrego zasobu rozwiązującego problem jest uważam za bardzo trafną i pomocną odpowiedź, a w tym przypadku mało sensu w podsumowaniu tej metody, której i tak nie mam czasu. "- 1" oznacza "odpowiedź brzmi: nieprzydatne". Nie widzę, jak wskazywanie na dobry zasób nie jest użyteczne. W rzeczywistości nie jest doskonały, ale naprawdę przydatny. – Boris

+0

Dla celów rejestracyjnych nie przesłałem (patrz [tutaj] (http://i.stack.imgur.com/gv7cN.png)), ale chciałbym wskazać [to pytanie] (http://meta.stackexchange.com/questions/225370/your-answer-is-in-another-castle-when-is-an-answer-not-an-answer), który określa zasady stosu wymiany dla tego typu odpowiedzi. Komentarz jest generowany automatycznie na podstawie czynności, którą wykonałem w kolejce do przeglądania, gdzie ten wpis zakończył się po tym, jak ktoś (prawdopodobnie ta sama osoba, która go zignorował) oznaczył go jako "niskiej jakości". – AstroCB