Obecnie rozwijam silnik gry, który wykorzystuje podpisane pola odległości jako technikę renderowania, aby wyświetlać płynną geometrię proceduralną (generowaną za pomocą prostych prymitywów, takich jak na razie w twoim łączu, z zamiarem zaimplementowania fraktali Julii i IFS w przyszłości). Ponieważ mój silnik koncentruje się na generowaniu procedur i musi definiować liczby w sposób, który czyni je przyjaznymi dla ray-marchera, wydaje mi się, że jestem w dobrym miejscu, aby odpowiedzieć na to pytanie: P.
Jeśli chodzi o przesyłanie strumieniowe, najprostszym rozwiązaniem jest użycie jakiegoś buforowanego typu i wrzucenie go na GPU, gdy chcesz przeprowadzić marsz promienny. Każdy element bufora jest typem złożonym (np. Struct w C / C ++), a każdy typ zawiera elementy określające, jaką funkcję należy użyć do jego reprezentowania, jego pozycję, obrót, skalę itp. Oraz średni kolor. Następnie proces upraszcza się do:
- Podziel scenę na zarządzalny podzbiór (zwróć uwagę, że algorytm marszowania promieni i tak jest częściowo wykonywany automatycznie przez algorytm marszowania promienia)
- Przekaż podzbiór do bufora wejściowego renderowania
- Przekaż bufor do GPU, jeśli jeszcze go nie ma, a następnie renderuj scenę za pomocą zwykłego tradycyjnego marszu promiennego. Będziesz musiał przeprowadzić pewnego rodzaju wyszukiwanie krok po kroku, aby ocenić, który element w buforze wejściowym jest najbliżej każdego promienia dla każdej iteracji marszera promienia, i musisz zastosować transformacje do każdego promienia (w takim przypadku musisz odwrócić obroty figury, zanim dotrą one do GPU) lub same funkcje odległości (przesuwając początek funkcji dla zmian pozycji, dostosowując np. długości boków sześciennych dla zmian skali itp.) Najprostszym podejściem jest po prostu zmodyfikowanie promieni przed przekazujesz je do rzeczywistej funkcji odległości rdzenia.
Jeśli chodzi o kolory figur, pamiętaj, że shadery pozwalają definiować zarówno złożone typy, jak i prymitywy;). To pozwala ci wrzucić wszystko do struktury w stylu C, a następnie przekazać te struktury z powrotem z funkcji odległości.
W moim silniku każda struktura zawiera odległość, kolor i identyfikator, który wiąże ją z odpowiednią definicją figury w buforze wejściowym. Każdy identyfikator jest wywnioskowany z otaczającego kontekstu odpowiedniej funkcji odległości (ponieważ moja funkcja mapowania zapętla się przez bufor wejściowy, aby znaleźć najbliższą liczbę dla każdego promienia dla każdego kroku, mogę bezpiecznie traktować wartość licznika pętli, gdy wywoływany jest każdy SDF jako identyfikator figury dla tej funkcji), podczas gdy wartości odległości są definiowane przy użyciu arbitralnego rdzenia SDF (nppoint - figure.pos
dla kuli), a kolory są albo definiowane na podstawie średniego koloru odpowiedniego elementu w buforze postaci (dlatego dlaczego warto zachować identyfikatory postaci) lub poprzez kolor proceduralny ważony w kierunku przechowywanej średniej (jednym przykładem może być wzięcie liczba iteracji dla pewnego punktu na żarówce Mandelbulb, mapowanie „przeciętnego koloru” z przestrzeni kolorów FP na przestrzeń kolorów całkowitych, a następnie użycie odwzorowanego koloru jako palety przez XOR'owanie go względem liczby iteracji).
Tekstury proceduralne to inne podejście, ale sam nigdy ich nie użyłem. iq przeprowadził sporo badań w tej dziedzinie i opublikował kilka ciekawych demonstracji na temat Shadertoy, dzięki czemu może to być jeden ze sposobów na zdobycie dodatkowych informacji.
Niezależnie od tego, czy kolor jest statyczny dla każdej figury, generowany proceduralnie, czy magicznie próbkowany z tekstury proceduralnej, podstawowa logika jest taka sama: abstrakcyjne figury do pewnego rodzaju pośredniego typu złożonego (np. Struktury), przechowują zarówno lokalną odległość, jak i lokalną kolor w instancji tego typu, a następnie przekaż typ złożony jako wartość zwracaną z funkcji odległości. W zależności od implementacji kolor wyjściowy może następnie przejść bezpośrednio do ekranu lub podążać za punktem kolizji do kodu oświetlenia.
Nie wiem, czy powyższe było wystarczająco jasne, czy nie, więc nie martw się pytaniem, czy coś nie ma sensu. Naprawdę nie mogę podać żadnych próbek kodu GLSL / cieniowania pikseli, ponieważ pracuję z HLSL i cieniowaniem obliczeniowym, ale z przyjemnością próbuję przejrzeć wszystko, czego nie napisałem poprawnie :).