Plik sceny waży dwieście megabajtów, a render zjada trzydzieści gigabajtów pamięci. Różnicę robi geometria, której w pliku nie ma — powstaje dopiero w rendererze, tuż przed pierwszym promieniem. Ten dodatek pokazuje, skąd się bierze i dlaczego jedno źle ustawione pole potrafi albo obciąć model, albo spowolnić render kilkukrotnie.
Modelarz oddaje siatkę bazową — kilka tysięcy czworokątów opisujących kształt, ale nie detal. Renderer, zanim cokolwiek policzy, dzieli każdy czworokąt na cztery mniejsze i wygładza pozycje wierzchołków (najczęściej schematem Catmulla-Clarka). Powtórzone n razy daje:
Podział adaptacyjny. Stała liczba iteracji marnuje pamięć na obiekty daleko od kamery: postać w tle dostaje ten sam detal co ta na pierwszym planie. Dlatego renderery liczą podział adaptacyjnie, w przestrzeni ekranu — dzielą dopóty, dopóki krawędź czworokąta nie zejdzie poniżej zadanej długości w pikselach. Obiekt oddalający się od kamery automatycznie dostaje mniej geometrii, bez ingerencji artysty.
To ma konsekwencję, która bywa zaskoczeniem: zużycie pamięci zależy od kadru. Ta sama scena renderowana z bliska i z daleka to dwa różne budżety. Ujęcie, które „nagle” przestało się mieścić w pamięci, często nie zmieniło się w żaden inny sposób niż zbliżeniem kamery.
Mając gęstą siatkę, renderer przesuwa każdy jej wierzchołek — najczęściej wzdłuż normalnej, o wartość odczytaną z tekstury (Rozdział 9). Wynik różni się od normal mapy w trzech miejscach, których nie da się podrobić: sylwetka na krawędzi obiektu jest faktycznie poszarpana, cień własny pada z prawdziwych wypukłości, a przecięcia z inną geometrią zachodzą tam, gdzie naprawdę.
Wariant wektorowy (vector displacement) przesuwa wierzchołek w dowolnym kierunku, nie tylko wzdłuż normalnej — dopiero to pozwala wyrzeźbić nawisy i zawinięcia, których displacement skalarny z definicji nie potrafi.
Zwróć uwagę na zero. Mapa zapisana ze środkiem w 0,5 i wczytana z zerem ustawionym na 0 przesunie całą powierzchnię na zewnątrz, zamiast rzeźbić w obie strony — model spuchnie równomiernie. To jeden z częstszych objawów „displacement nie działa tak, jak w programie do rzeźbienia”.
Tu pojawia się problem, który wynika wprost z Rozdziału 13. BVH buduje pudełka wokół geometrii, żeby móc odrzucać promienie bez testowania trójkątów. Ale przesunięcie jest znane dopiero po odczytaniu tekstury dla każdego wierzchołka — a renderer musi znać rozmiar pudełka wcześniej, żeby w ogóle zdecydować, które fragmenty siatki wygenerować.
Rozwiązanie jest niewygodne, ale jedyne: podajesz z góry, o ile maksymalnie geometria może się przesunąć. Renderer powiększa pudełka o tę wartość i dopiero potem liczy.
Objaw zbyt małych granic jest charakterystyczny i łatwy do rozpoznania: geometria wygląda, jakby ktoś ściął jej wierzchołki płaszczyzną — bo dokładnie to się stało. Objaw zbyt dużych jest podstępniejszy, bo obraz jest poprawny; widać tylko czas renderu, który nie ma uzasadnienia w tym, co na obrazku.
W Arnoldzie to grupa na siatce: subdiv_type (catclark albo linear), subdiv_iterations, subdiv_adaptive_metric i subdiv_pixel_error dla podziału adaptacyjnego, oraz disp_height, disp_zero_value i disp_padding — to ostatnie jest właśnie polem granic z sekcji wyżej. RenderMan dziedziczy tu wprost po REYES-ie i mówi o dicingu do mikropoligonów; Karma wystawia analogiczne kontrolki na prymie USD.
Kolejność diagnozy przy renderze, który nie mieści się w pamięci: najpierw sprawdź iteracje podziału na najcięższych obiektach, potem czy podział jest adaptacyjny, a dopiero na końcu tekstury. Zejście z n=5 na n=4 na jednym obiekcie tła potrafi zwolnić więcej pamięci niż cała reszta optymalizacji razem.
Osobna pułapka: displacement psuje instancing z Rozdziału 17 wtedy, gdy każda instancja dostaje inną mapę — wspólna siatka przestaje być wspólna i oszczędność pamięci znika. Instancje z tą samą mapą displacement zachowują się normalnie.
Geometrię mamy już wygenerowaną i przesuniętą. Dodatek AI zajmuje się drugą stroną tej samej pracy: językami, w których dziś opisuje się materiały pokrywające tę geometrię.