Ostre rogi z czcionkami z podpisanymi polami odległości

49

W tym artykule Valve Distance Fields (SDF) zostało przedstawione jako szybkie rozwiązanie umożliwiające niezależne od rozdzielczości renderowanie czcionek przez Valve .

Mam już działające rozwiązanie Valve, ale chciałbym zachować ostrość na rogach. Valve twierdzi, że ich metoda pozwala osiągnąć ostre rogi za pomocą drugiego kanału teksturowego ANDed z podstawowym, ale brakuje wyjaśnienia, w jaki sposób ten drugi kanał zostałby wygenerowany.

W rzeczywistości w tym dokumencie pozostało wiele szczegółów implementacyjnych.

Chciałbym wiedzieć, czy ktoś z was mógłby wskazać mi kierunek, w jaki sposób renderować czcionki SDF z ostrymi narożnikami.

Felipe Lira
źródło
W rzeczywistości Adam już opublikował kod źródłowy w shadertoy. Oto link: shadertoy.com/view/ltXSDB
Felipe Lira
Podnieciłeś mnie. Opublikował rzeczy beziera na shadertoy, ale nie na polu odległości tekstury!
Alan Wolfe
@AlanWolfe Wydaje mi się, że zrobił to tylko dla ustawionych proceduralnie krzywych Beziera. Nie jestem pewien wysiłku włożonego w integrację tego z biblioteką renderującą ttf. Kiedy będę miał trochę czasu, spojrzę na to.
Felipe Lira,
wygląda na to, że ma trochę magicznego sosu po stronie przechowywania i wyszukiwania odległości od tekstury. Bez tekstury w grze w przykładach shadertoy brakuje tej części równania.
Alan Wolfe,
Trochę za późno na imprezę, ale ten starszy wątek z reddit ma mnóstwo informacji na temat różnych metod poprawy ostrości renderowania opartego na SDF: reddit.com/r/gamedev/comments/2879jd/…
Necrolis

Odpowiedzi:

7

Adam Simmons wykonał kilka interesujących prac w tej dziedzinie. Nie wiem dokładnie, jak to osiąga, ale jego rendering wektorowy oparty na SDF jest najostrzejszy, jaki widziałem w praktyce poza Valve. http://twitter.com/adamjsimmons/status/611677036545863680

warrenm
źródło
Oczywiście nie mam wszystkich szczegółów, ale wydaje mi się, że ta osoba po prostu użyła pola pseudodystansowego zamiast zwykłego, co zostało już zademonstrowane w artykule z 2006 roku przez Qin, McCool i Kaplana: Glify wektorowe odwzorowywane w czasie rzeczywistym ”, o których jest również mowa w dokumencie Valve. Wpływa tylko na elementy konturu i nie poprawia wyglądu narożników. Podejrzewam, że jest tak ostry, ponieważ wykorzystuje niepraktycznie duże tekstury pól odległości. Mogę się jednak mylić.
Detheroc,
69

EDYCJA: Proszę zobaczyć moją drugą odpowiedź z konkretnym rozwiązaniem.

Dokładnie rozwiązałem ten problem ponad rok temu w pracy magisterskiej. W dokumencie Valve pokazują, że możesz ORAZ dwa pola odległości, aby to osiągnąć, co działa, dopóki masz tylko jeden wypukły narożnik. W przypadku wklęsłych narożników potrzebujesz również operacji OR. Ten facet opracował niejasny system przełączania między dwiema operacjami za pomocą czterech kanałów tekstur.

Istnieje jednak znacznie prostsza operacja, która może ułatwić zarówno AND, jak i OR, w zależności od sytuacji, i to jest główna idea mojej tezy: mediana trzech . Zasadniczo używasz dokładnie trzech kanałów (idealnych dla RGB), które są całkowicie wymienne, i łączysz je za pomocą operacji mediany (wybierz środkową wartość z trzech).

Aby dostosować się do wygładzania, nie pracujemy tylko z wartościami logicznymi, ale wartościami zmiennoprzecinkowymi, a operacja AND staje się minimum, a OR staje się maksymalnie dwiema wartościami. Mediana trzech może rzeczywiście zrobić oba: jeśli a < b , dla ( a , a , b ), mediana jest minimalna, a dla ( a , b , b ) jest maksymalna.

Proces renderowania jest nadal niezwykle prosty. Cały moduł cieniujący fragmenty wraz z wygładzaniem może wyglądać mniej więcej tak:

int main() {
    // Bilinear sampling of the distance field
    vec3 s = texture2D(sdf, p).rgb;
    // Acquire the signed distance
    float d = median(s.r, s.g, s.b) - 0.5;
    // Weight between inside and outside (anti-aliasing)
    float w = clamp(d/fwidth(d) + 0.5, 0.0, 1.0);
    // Combining the background and foreground color
    gl_FragColor = mix(outsideColor, insideColor, w);
}

Tak więc jedyną różnicą w stosunku do oryginalnej metody jest obliczenie mediany zaraz po próbkowaniu tekstury. Trzeba będzie jednak zaimplementować funkcję mediany, co można zrobić za pomocą zaledwie 4 min / maks . Operacji .

Teraz oczywiście pytanie brzmi: jak zbudować takie trzykanałowe pole odległości?I to jest trudna część. Najbardziej oczywistym podejściem, które podjąłem na początku, było rozłożenie wejściowego kształtu / glifu na trzy składniki, a następnie wygenerowanie konwencjonalnego pola odległości z każdego z nich. Zasady tego rozkładu nie są tak skomplikowane. Po pierwsze, obszar z co najmniej 2 z 3 kanałami jest wewnątrz. Następnie, jeśli wyobrażasz to sobie jako kanały kolorów RGB, wypukłe rogi muszą być wykonane z drugiego koloru, a jego dwa podstawowe elementy muszą być skierowane na zewnątrz. Wklęsłe rogi są odwrotne: dwa kolory wtórne otaczają ich wspólny kolor podstawowy, a klin między miejscem, w którym obie krawędzie są skierowane do wewnątrz, jest biały. Zauważyłem również, że konieczne jest wypełnienie, gdy dwa kolory podstawowe lub dwa kolory wtórne dotknęłyby się, aby uniknąć artefaktów (na przykład w środkowym obrysie litery „N”

Poniższy obraz to przykładowy rozkład wygenerowany przez program na podstawie mojej tezy:

Wielokanałowy rozkład glifów

Takie podejście ma jednak pewne wady. Jednym z nich jest to, że efekty specjalne, takie jak kontury i cienie, nie będą już działać poprawnie. Na szczęście wymyśliłem także drugą, znacznie bardziej elegancką metodę, która generuje pola odległości bezpośrednio, a nawet obsługuje wszystkie efekty graficzne. Jest to również uwzględnione w mojej pracy magisterskiej, a więc ma też ponad rok. Nie zamierzam teraz podawać więcej szczegółów, ponieważ obecnie piszę artykuł szczegółowo opisujący tę drugą technikę, ale opublikuję ją tutaj, jak tylko się skończy.

Tak czy inaczej, oto przykład różnicy w jakości. Rozdzielczość tekstury jest taka sama na każdym obrazie, ale lewa używa zwykłej tekstury, środkowa używa zwykłego pola odległości, a prawa używa mojego trzykanałowego pola odległości. Narzut wydajnościowy to tylko różnica między próbkowaniem tekstury RGB a monochromatyczną.

wprowadź opis zdjęcia tutaj

Detheroc
źródło
5
Świetna pierwsza odpowiedź, witamy w Computer Graphics SE! :) Czy Twoja praca dyplomowa jest publicznie dostępna? (A może po tym, jak skończysz mówić?). Jeśli tak, prawdopodobnie bardzo pomocne byłoby również link do tego.
Martin Ender,
To ma być publicznie dostępne, ale wygląda na to, że szkoła jeszcze tego nie wystawiła. W każdym razie wolałbym nie rozpowszechniać go teraz, ponieważ artykuł, który piszę, naprawdę lepiej wyjaśni ważne części i skupi się na tym, jak go wdrożyć, a wkrótce powinien zostać ukończony.
Detheroc,
@Detheroc Powiadom o tym tutaj i na gamedev Q, kiedy skończysz z artykułem. Wyjaśnienie wciąż nie jest dla mnie w 100% jasne. Sugerowałbym pokazywanie kompozycji krok po kroku na obrazach.
Inżynier
1
chciałbym móc odtworzyć bieżące wyniki, nawet jeśli nie są tak dobre, jak Twoje przyszłe wyniki, +1 do udostępnienia dowolnych szczegółów. bardzo ekscytujące. Czy zastanawiałeś się nad zastosowaniem którejś z technik do marszu promiennego (śledzenie kuli)? W tomach tekstur lub podobnych ...
Alan Wolfe
4
Teza jest publicznie dostępna tutaj: dspace.cvut.cz/bitstream/handle/10467/62770/…
Romain Guy
43

Przepraszam za długie oczekiwanie, ale stało się oczywiste, że chociaż obiecany artykuł jest w zasadzie kompletny, proces publikacji zajmie trochę czasu. Dlatego zamiast tego przygotowałem program open source z moim nowym wielokanałowym algorytmem budowy pola odległości, msdfgen , który możesz wypróbować już teraz.

Jest dostępny na GitHub: https://github.com/Chlumsky/msdfgen

(Jestem nowy, więc daj mi znać, jeśli coś jest nie tak z repozytorium).

Ktoś zapytał również o to, jak wypada w porównaniu z większym monochromatycznym polem odległości, więc tutaj jest zwiastun różnicy jakości. Jednak tak naprawdę zależy to od konkretnej czcionki i nie powiedziałbym, że zawsze jest to warte dodatkowych danych.

Wielokanałowe pole odległości 16x16 Monochromatyczne pole odległości 32x32

Detheroc
źródło
3

Dość ciekawe! Jestem autorem papieru dystansowego z zaworem. Przepraszam, że jest to trochę rzadkie w szczegółach implementacji. Jako przyszłą pracę podałem tylko przykład z dwoma kanałami - nie miałem generatora. Doszedłem do wniosku, że generowanie sdf o wysokiej rozdzielczości, a następnie segmentacja na podstawie kąta gradientu sdf byłoby rozsądną taktyką. Ale nigdy do tego nie doszło. Każdy schemat wielokanałowy należy porównać z wykorzystaniem danych jednokanałowych o wyższej rozdzielczości o tej samej powierzchni pamięci, aby uzyskać współczynniki powiększenia wymagane przez aplikację.

Chris Green
źródło
0

W żadnym wypadku nie jestem ekspertem w tej dziedzinie, ale możesz teoretycznie zachować ostre rogi w monochromatycznym pseudo-SDF, jeśli użyjesz albo filtra dwustronnego, kierunkowego filtra dwububkowego zamiast standardowego filtra dwuliniowego. Oprócz oczywistej korzyści z oszczędzania pamięci, możesz również mieć wiele kanałów dla wielokolorowych naklejek SDF.

Alternatywnie, jeśli nie masz nic przeciwko użyciu drugiego kanału, możesz również spróbować mieć jeden kanał dla odległości poziomej, a drugi dla odległości pionowej, i użyć piramidy energetycznej Różnica Laplaceana (DoL) do skompresowania tekstury, aby nadmiarowe informacje nie były nie będą rejestrowane.

Trzecim i ostatnim teoretycznym rozwiązaniem byłoby eksperymentowanie z teksturą próbkowaną sześciokątnie za pomocą adresowania zestawu macierzy.

Niestety, nie mam obecnie środków do testowania moich pomysłów i nie mogłem znaleźć żadnych dokumentów opisujących lub testujących coś podobnego do moich pomysłów. Wkrótce dołączę wszystkie odpowiednie artykuły, do których otrzymałem informacje / pomysły.

Amaroq Starwind
źródło