Na czym polega najnowocześniejsze renderowanie tekstu w OpenGL od wersji 4.1? [zamknięte]

Jest już kilka pytań dotyczących renderowania tekstu w OpenGL, takich jak:

Ale przede wszystkim to, co jest omawiane, to renderowanie teksturowanych quadów za pomocą potoku fixed-function. Z pewnością shadery muszą znaleźć lepszy sposób.

Nie jestem zbytnio zainteresowany internacjonalizacją, większość moich ciągów znaków będzie etykietami Wykresów (Data i godzina lub czysto liczbowe). Ale działki będą ponownie renderowane w częstotliwość odświeżania ekranu i może być sporo tekstu (nie więcej niż kilka tysięcy glifów na ekranie, ale na tyle, że układ przyspieszany sprzętowo byłby miły).

Jakie jest zalecane podejście do renderowania tekstu przy użyciu nowoczesnego OpenGL? (Powoływanie się na istniejące oprogramowanie przy użyciu tego podejścia jest dobrym dowodem na to, że działa dobrze)

  • shadery geometrii, które akceptują np. położenie i orientację oraz sekwencję znaków i emitują teksturowane quady
  • shadery geometrii, które renderują czcionki wektorowe
  • Jak wyżej, ale zamiast tego używając shaderów teselacji
  • Shader obliczeniowy do rasteryzacji czcionek
Author: Community, 2011-03-10

5 answers

Renderowanie konturów, o ile nie wyrenderuje się łącznie tylko kilkunastu znaków, pozostaje "no go" ze względu na liczbę wierzchołków potrzebnych do przybliżenia krzywizny na znak. Chociaż istnieją podejścia do oceny krzywych Beziera w shaderze pikseli zamiast tego, cierpią one z powodu braku łatwego antyaliasingu, co jest trywialne przy użyciu kwadratu z teksturą mapy odległości, A ocena krzywych w shaderze jest nadal znacznie droższa niż jest to konieczne.

Najlepszy kompromis pomiędzy "szybkie "i" jakość " to nadal teksturowane quady z podpisaną teksturą pola odległości. Jest to bardzo nieznacznie wolniejsze niż użycie zwykłego kwadratu o zwykłej fakturze, ale nie tak bardzo. Jakość z drugiej strony, jest w zupełnie innym polu. Wyniki są naprawdę oszałamiające, jest tak szybko, jak to możliwe, a efekty, takie jak blask, są trywialnie łatwe do dodania. Ponadto, technika może być ładnie obniżona do starszego sprzętu, w razie potrzeby.

Zobacz słynny Papier Valve dla technika.

Technika ta jest koncepcyjnie podobna do działania powierzchni ukrytych (metaballi itp.), choć nie generuje wielokątów. Działa w całości w pixel shader i pobiera odległość pobraną z tekstury jako funkcję odległości. Wszystko powyżej wybranego progu (zwykle 0,5) jest "w", Wszystko inne jest "na zewnątrz". W najprostszym przypadku, na 10-letnim sprzęcie nie obsługującym shaderów, ustawienie progu testu alfa na 0.5 zrobi dokładnie to samo (choć bez efekty specjalne i antyaliasing).
Jeśli ktoś chce dodać trochę większą wagę do czcionki( Faux bold), nieco mniejszy próg poradzi sobie bez modyfikowania pojedynczej linii kodu (wystarczy zmienić Mundur "font_weight"). Dla efektu blasku, po prostu uważa się wszystko powyżej jednego progu jako "w", a wszystko powyżej drugiego (mniejszego) progu jako "Na zewnątrz, ale w blasku", a LERPs między nimi. Podobnie działa antyaliasing.

Używając 8-bitowej wartości odległości podpisanej zamiast pojedynczego bitu, technika ta zwiększa efektywną rozdzielczość mapy tekstur 16-krotnie w każdym wymiarze (zamiast czerni i bieli używane są wszystkie możliwe odcienie, dlatego mamy 256 razy więcej informacji przy użyciu tej samej pamięci masowej). Ale nawet jeśli powiększysz znacznie ponad 16x, wynik nadal wygląda na całkiem akceptowalny. Długie proste linie w końcu staną się nieco wiotkie, ale nie będzie typowych" blokowych " artefaktów próbkowania.

Możesz użyć shadera geometry do generowania quady poza punktami (zmniejszają przepustowość magistrali), ale szczerze mówiąc zyski są raczej marginalne. To samo dotyczy renderowania postaci z instancji, jak opisano w GPG8. Narzut instancji jest amortyzowany tylko wtedy, gdy masz lot tekstu do narysowania. Moim zdaniem zyski nie mają związku z dodaną złożonością i brakiem możliwości obniżenia ratingu. Dodatkowo, jesteś ograniczony ilością stałych rejestrów lub musisz czytać z obiektu bufora tekstury, który nie jest optymalny dla pamięci podręcznej spójność (a intencją było Optymalizacja na początek!).
Prosty, zwykły stary bufor wierzchołków jest tak samo szybki (być może szybszy), jeśli zaplanujesz przesyłanie z wyprzedzeniem i będzie działać na każdym sprzęcie zbudowanym w ciągu ostatnich 15 lat. Nie ogranicza się do żadnej określonej liczby znaków w czcionce ani do określonej liczby znaków do renderowania.

Jeśli masz pewność, że nie masz więcej niż 256 znaków w czcionce, tablice tekstur mogą być warte rozważenie usunięcia pasma magistrali w podobny sposób, jak generowanie quadów z punktów w shaderze geometry. Podczas używania tekstury tablicy, współrzędne tekstury wszystkich quadów mają identyczne, stałe współrzędne s i t i różnią się tylko współrzędną r, która jest równa indeksowi znaków do renderowania.
Ale podobnie jak w przypadku innych technik, oczekiwane zyski są marginalne kosztem niekompatybilności ze sprzętem poprzedniej generacji.

Jest poręczny narzędzie Jonathana Dummera do generowania tekstur odległości: strona opisu

Update:
Jak ostatnio wspomniano w Programmable Vertex Pulling (D. Rákos, "OpenGL Insights", str. 239), nie ma znaczącego dodatkowego opóźnienia lub narzutu związanego z programowym pobieraniem danych wierzchołków z shadera na najnowszych generacjach GPU, w porównaniu do robienia tego samego przy użyciu standardowej stałej funkcji.
Również najnowsze generacje GPU 1536kib na nvidia Kepler), więc można się spodziewać niespójnego problemu z dostępem, gdy wyrywa się losowe przesunięcia dla narożników quad z tekstury bufora, będąc mniejszym problemem.

To sprawia, że pomysł pobierania stałych danych (takich jak rozmiary quad) z tekstury bufora jest bardziej atrakcyjny. Hipotetyczna implementacja mogłaby zatem zredukować do minimum transfery PCIe i pamięci, a także pamięci GPU to:

  • prześlij tylko indeks znaków (po jednym na każdy znak, który ma być wyświetlony) jako jedyne wejście do modułu cieniującego wierzchołki, który przekazuje ten indeks i gl_VertexID, i zwiększ go do 4 punktów w module cieniującym geometry, nadal mając indeks znaków i identyfikator wierzchołka (będzie to "gl_primitiveID udostępnione w module cieniującym wierzchołki") jako jedyne atrybuty, i przechwyć to poprzez sprzężenie zwrotne transformacji.
  • będzie to szybkie, ponieważ istnieją tylko dwa atrybuty wyjściowe (główne wąskie gardło w GS), i jest blisko "no-op" inaczej w obu etapach.
  • Bind teksturę bufora, która zawiera, dla każdego znaku w czcionce, teksturowane wierzchołki czworokąta względem punktu bazowego (są to zasadniczo "metryki czcionek"). Dane te mogą być skompresowane do 4 liczb na kwadrat, przechowując tylko przesunięcie lewego dolnego wierzchołka i kodując szerokość i Wysokość pola wyrównanego do osi (zakładając połowy pływaków, będzie to 8 bajtów stałego bufora na znak -- typowy Czcionka 256 znaków może zmieścić się całkowicie w 2kiB pamięci podręcznej L1).
  • Ustaw uniform dla linii bazowej
  • wiąże teksturę bufora z poziomymi przesunięciami. Te mogłyby być prawdopodobnie nawet obliczone na GPU, ale jest to znacznie łatwiejsze i bardziej wydajne dla tego typu rzeczy na CPU, ponieważ jest to operacja ściśle Sekwencyjna i wcale nie trywialna (pomyśl o kerningu). Wymagałoby to również kolejnego przejścia sprzężenia zwrotnego, który byłby kolejnym punktem synchronizacji.
  • Render the wcześniej wygenerowane dane z bufora sprzężenia zwrotnego, shader wierzchołków pobiera poziome przesunięcie punktu bazowego i przesunięcia narożnych wierzchołków z obiektów bufora (używając prymitywnego identyfikatora i indeksu znaków). Oryginalny identyfikator przesłanych wierzchołków jest teraz naszym "prymitywnym identyfikatorem" (pamiętaj, że GS zamieniło wierzchołki w quady).

W ten sposób można by idealnie zredukować wymagane pasmo wierzchołków o 75% (amortyzowane), chociaż byłoby to tylko w stanie renderować pojedyncza linia. Jeśli ktoś chciałby móc renderować kilka linii w jednym wywołaniu rysowania, musiałby dodać linię bazową do tekstury bufora, zamiast używać jednolitej (zmniejszając przyrosty przepustowości).

Jednak nawet zakładając redukcję o 75% - ponieważ dane wierzchołków do wyświetlania "rozsądnych" ilości tekstu są tylko około 50-100kib (co jest praktycznie zero dla GPU lub magistrali PCIe) - nadal wątpię, że dodatkowa złożoność i utrata kompatybilności wstecznej jest naprawdę warto. Zmniejszenie zera o 75% to nadal tylko zero. Przyznaję, że nie próbowałem powyższego podejścia, a więcej badań byłoby potrzebne, aby złożyć prawdziwie kwalifikowane oświadczenie. Ale i tak, chyba że ktoś potrafi wykazać naprawdę oszałamiającą różnicę w wydajności (używając "normalnych" ilości tekstu, a nie miliardów znaków!), mój punkt widzenia pozostaje, że dla danych wierzchołków prosty, zwykły stary bufor wierzchołków jest na tyle dobry, że można go uznać za część "najnowocześniejszego rozwiązania". To proste i proste, działa i działa dobrze.

Nawiązując już do "OpenGL Insights" powyżej, warto również zwrócić uwagę na Rozdział "renderowanie kształtów 2D przez pola odległości" autorstwa Stefana Gustavsona, który szczegółowo wyjaśnia renderowanie pól odległości.

Aktualizacja 2016:

Tymczasem istnieje kilka dodatkowych technik, które mają na celu usunięcie artefaktów zaokrąglania narożników, które stają się niepokojące w ekstremalnych powiększenia.

Jedno podejście po prostu używa pól pseudo-odległości zamiast pól odległości (różnica polega na tym, że odległość jest najkrótszą odległością nie do rzeczywistego konturu, ale do konturu lub wyimaginowanej linii wystającej ponad krawędź). Jest to nieco lepsze i działa z tą samą prędkością (identyczny shader), używając tej samej ilości pamięci tekstur.

Inne podejście wykorzystuje medianę z trzech w trójkanałowych szczegółach tekstury i implementacji [[80]}dostępny na github . Ma to być poprawa w stosunku do hacków and-or używanych wcześniej do rozwiązania problemu. Dobra jakość, lekko, prawie nie zauważalnie, wolniej, ale wykorzystuje trzy razy więcej pamięci tekstur. Ponadto, dodatkowe efekty (np. blask) są trudniejsze do uzyskania.

Wreszcie, przechowywanie rzeczywistych krzywych Beziera tworzących znaki i ocenianie ich w cieniowaniu fragmentów stało się praktyczne , z nieco gorszą wydajnością (ale nie tak bardzo, że jest to problem) i oszałamiające wyniki nawet przy najwyższych powiększeniach.
Demo WebGL renderowanie dużego pliku PDF z tą techniką w czasie rzeczywistym dostępne tutaj .

 182
Author: Damon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-02 11:24:14

Http://code.google.com/p/glyphy/

Główną różnicą między Glify a innymi rendererami OpenGL opartymi na SDF jest to, że większość innych projektów przykłada SDF do tekstury. Ma to wszystkie typowe problemy, które ma pobieranie próbek. Ie. zniekształca kontur i jest niskiej jakości. Glify zamiast tego reprezentują SDF za pomocą rzeczywistych wektorów przesyłanych do GPU. powoduje to bardzo wysoką jakość renderowania.

Minusem jest to, że kod jest dla iOS z OpenGL ES. Prawdopodobnie zrobię OpenGL dla systemu Windows / Linux 4.port x (mam nadzieję, że autor doda jakąś prawdziwą dokumentację).

 13
Author: Display Name,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-08 19:11:46

Najbardziej rozpowszechnioną techniką są wciąż teksturowane quady. Jednak w 2005 roku Loria opracowała coś, co nazywa się teksturami wektorowymi, tj. renderowanie grafiki wektorowej jako tekstur na prymitywach. Jeśli używa się tego do konwersji czcionek TrueType lub OpenType na teksturę wektorową, otrzymuje się to:

Http://alice.loria.fr/index.php/publications.html?Paper=VTM@2005

 11
Author: datenwolf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-10 17:02:53

Dziwi mnie, że dziecko Marka Kilgarda, NV_path_rendering (NVpr), nie zostało wspomniane przez żadnego z powyższych. Chociaż jego cele są bardziej ogólne niż renderowanie czcionek, może również renderować tekst z czcionek i z kerningiem. Nie wymaga nawet OpenGL 4.1, ale w tej chwili jest to rozszerzenie tylko dla dostawców / Nvidii. Zasadniczo zmienia czcionki w ścieżki za pomocą glPathGlyphsNV, co zależy od biblioteki freetype2, aby uzyskać metryki, itp. Następnie możesz również uzyskać dostęp do informacji kerningu za pomocą glGetPathSpacingNV i użyć NVpr ogólny mechanizm renderowania ścieżek do wyświetlania tekstu z wykorzystaniem ścieżek - "konwertowanych" czcionek. (Umieszczam to w cudzysłowach, ponieważ nie ma prawdziwej konwersji, krzywe są używane tak, jak jest.)

Nagrane demo dla możliwości czcionek NVpr nie jest niestety szczególnie imponujące. (Może ktoś powinien zrobić coś podobnego do much snazzier SDF demo można znaleźć na intertubach...)

Rozpoczyna się prezentacja nvpr API 2011 dla części czcionek tutaj i dalej w następnej części; trochę niefortunne jest to, jak ta prezentacja jest podzielona.

Bardziej ogólne materiały na temat NVpr:

  • Nvidia NVpr hub, ale niektóre materiały na stronie docelowej nie są najbardziej aktualne.]}
  • Papier Siggraph 2012 dla mózgów metody renderowania ścieżek, zwanej "stencil, then cover" (StC); artykuł wyjaśnia również krótko, jak działają konkurencyjne technologie, takie jak Direct2D. Bity związane z czcionką zostały [[28]} załącznik do referatu. Istnieją również niektóre dodatki, takie jak filmy / dema .
  • prezentacja GTC 2014 dla statusu aktualizacji; w skrócie: jest teraz obsługiwany przez Google Skia (Nvidia dostarczyła kod na przełomie 2013 i 2014), który z kolei jest używany w Google Chrome i [niezależnie od Skia, myślę] w wersji beta Adobe Illustrator CC 2014{[24]]}
  • oficjalna dokumentacja w rejestrze rozszerzeń OpenGL
  • USPTO ma udzielono co najmniej czterech patentów Kilgard/Nvidia w związku z NVpr, z których prawdopodobnie powinieneś być świadomy, jeśli chcesz zaimplementować StC samodzielnie: US8698837, US8698808, US8704830 i US8730253 . Zauważ, że istnieje około 17 więcej dokumentów USPTO związanych z tym jako "również opublikowane jako", z których większość to zgłoszenia patentowe, więc jest całkowicie możliwe, że więcej patentów może być udzielonych od nich.

A ponieważ słowo "szablon" nie wywołał żadnych trafień na tej stronie przed moją odpowiedzią, wygląda na to, że podzbiór tak społeczności, która uczestniczyła na tej stronie, mimo że była dość liczna, nie była świadoma darmowych metod teselacji, opartych na buforze szablonów do renderowania ścieżek / czcionek w ogóle. Kilgard ma post podobny do FAQ na forum opengl , który może wyjaśnić, w jaki sposób metody renderowania ścieżek bez teselacji różnią się od standardowej grafiki 3D bog, mimo że nadal używają GPU [GP]. (NVpr potrzebuje Chipa zdolnego do CUDA.)

Kilgard jest również autorem klasycznego "a Simple OpenGL-based API for Texture Mapped Text", SGI, 1997, którego nie należy mylić z nvpr opartym na szablonach, który zadebiutował w 2011 roku.

Większość, jeśli nie wszystkie najnowsze metody omówione na tej stronie, w tym metody oparte na szablonach, takie jak NVpr lub metody oparte na SDF, takie jak Glify (o których nie dyskutuję tutaj, ponieważ inne odpowiedzi już to obejmują) mają jednak jedno ograniczenie: nadają się do dużych wyświetlaczy tekstowych na konwencjonalnych monitorach (~100 DPI) bez postrzępień na dowolnym poziomie skalowania, a także wyglądają ładnie, nawet przy małych rozmiarach, na wyświetlaczach o wysokiej rozdzielczości, podobnych do siatkówki. Nie zapewniają jednak w pełni tego, co daje Microsoft Direct2D + DirectWrite, a mianowicie podpowiedzi o małych glifach na głównych wyświetlaczach. (Dla wizualnego badania hinting w ogóle patrz ten typotheque Strona na przykład. Bardziej dogłębnym zasobem jest na antigrain.com.)

Nie jestem świadomy żadnych open & productized OpenGL oparte rzeczy, które mogą zrobić to, co Microsoft może z hinting w tej chwili. (Przyznaję ignorancję Dla OS X GL/Quartz firmy Apple, ponieważ według mojej najlepszej wiedzy Apple nie opublikowało, jak robią renderowanie czcionek / ścieżek opartych na GL. Wydaje się, że OS X, w przeciwieństwie do MacOS 9, nie robi aluzji w ogóle, co denerwuje niektórych ludzi. W każdym razie, istnieje jeden 2013 pracy badawczej, która dotyczy hinting poprzez OpenGL shadery napisane przez Nicolasa P. Rougiera z INRII; prawdopodobnie warto przeczytać, jeśli chcesz zrobić hinting z OpenGL. Chociaż może się wydawać, że biblioteka taka jak freetype wykonuje już całą pracę, jeśli chodzi o hinting, tak naprawdę nie jest tak z następującego powodu, który cytuję z artykułu: {]}

Biblioteka FreeType może rasteryzować glif za pomocą antyaliasingu subpikselowego w trybie RGB. Jest to jednak tylko połowa problemu, ponieważ chcemy również osiągnąć subpiksel pozycjonowanie dla dokładnego umieszczania glifów. Wyświetlanie teksturowanego quada na ułamkowe współrzędne pikseli nie rozwiązują problemu, ponieważ skutkują jedynie teksturą interpolacja na poziomie całego piksela. Zamiast tego chcemy osiągnąć precyzyjną zmianę (między 0 a 1) w domenie subpikseli. Można to zrobić w fragment shader [...].

Rozwiązanie nie jest do końca trywialne, więc nie będę próbował tego tutaj wyjaśniać. (Artykuł jest ogólnodostępny.)


One inną rzeczą, której nauczyłem się z artykułu Rougiera (a której Kilgard chyba nie wziął pod uwagę), jest to, że uprawnienia czcionek, które be (Microsoft+Adobe) stworzyły nie jedną, ale dwie metody specyfikacji kerninga. Stara jest oparta na tak zwanej tabeli kern i jest obsługiwana przez freetype. Nowa nosi nazwę GPOS i jest obsługiwana tylko przez nowsze biblioteki czcionek, takie jak HarfBuzz czy pango w świecie wolnego oprogramowania. Ponieważ NVpr nie obsługuje żadnej z tych bibliotek, kerning może nie działać po wyjęciu z pudełka z NVpr dla niektórych nowych czcionek; są takie, które najwyraźniej są dzikie, zgodnie z ta dyskusja na forum .

Wreszcie, jeśli potrzebujesz wykonać złożony układ tekstu (CTL) wydaje się, że obecnie masz pecha z OpenGL, ponieważ wydaje się, że żadna biblioteka oparta na OpenGL nie istnieje do tego celu. (Z drugiej strony DirectWrite może obsługiwać CTL.) Istnieją biblioteki open-source, takie jak HarfBuzz, które mogą renderować CTL, ale nie wiem, jak można je dobrze uruchomić (jak przy użyciu metod opartych na szablonach) poprzez OpenGL. Prawdopodobnie będziesz musiał napisać kod kleju, aby wyodrębnić ponownie ukształtowane kontury i wprowadzić je do rozwiązań opartych na NVpr lub SDF jako ścieżki.

 6
Author: Fizz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-20 10:18:27

Myślę, że najlepiej byłoby przyjrzeć się grafice {[2] } z OpenGL backend.

Jedynym problemem, jaki miałem podczas tworzenia prototypu z rdzeniem 3.3, było przestarzałe użycie funkcji w backendzie OpenGL. To było 1-2 lata temu, więc sytuacja mogła się poprawić...

W każdym razie, mam nadzieję, że w przyszłości sterowniki graficzne OpenGL będą implementować OpenVG.

 3
Author: Orhun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-10 19:11:46