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:
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ą.