Rozdział 15 pokazał, że path tracer buduje ścieżki: kamera, odbicie, kolejne odbicie, światło. Rozdział 19 wspomniał o AOV-ach jako o gotowych buforach. Między jednym a drugim jest mechanizm, którego książka dotąd nie nazwała — sposób, w jaki mówisz rendererowi „daj mi osobno tylko to, co odbiło się od metalu po drugim odbiciu”.
Weź ścieżkę z Rozdziału 15: promień wychodzi z kamery, trafia w ścianę i odbija się rozproszenie, potem trafia w drugą ścianę i znów rozprasza, wreszcie trafia w światło. Renderer wykonał trzy decyzje i każdą z nich zna. Zapisane literami:
Alfabet jest krótki. Obok C i L są typy rozproszenia: D (diffuse), G (glossy, czyli rozmyte odbicie z Rozdziału 11) i S (specular, idealnie lustrzane z Rozdziału 7). Do tego kierunek zdarzenia: R (odbicie, reflection) albo T (przejście, transmission). Typ i kierunek zapisuje się razem w nawiasach ostrych, więc rozproszone odbicie to <RD>, a załamanie przez szkło to <TS>.
Skoro każda ścieżka jest słowem, to wybranie interesującej nas grupy jest dopasowaniem wzorca. LPE dokłada do alfabetu dwa operatory znane z wyrażeń regularnych: . (dowolne zdarzenie) i * (poprzedni element zero lub więcej razy).
Różnica między tymi dwoma wyrażeniami to dokładnie różnica między AOV-em direct diffuse a diffuse. Pośredni dostajesz, odejmując jedno od drugiego — albo pisząc wzorzec, który wymaga co najmniej dwóch zdarzeń przed światłem.
Kilka wzorców, które warto rozpoznawać:
Ostatni wiersz jest tu najważniejszy. C.*L obejmuje każdą ścieżkę, więc jeśli zdefiniujesz zestaw AOV-ów, których wzorce są rozłączne i razem pokrywają C.*L, to ich suma jest matematycznie równa beauty — nie „mniej więcej”, tylko dokładnie. Renderer nie liczy ich osobno; liczy ścieżki raz i wrzuca wkład każdej do tego kubełka, do którego pasuje.
To wyjaśnia dwie rzeczy, które w compingu bywają zaskoczeniem. Po pierwsze: dodanie kolejnych AOV-ów prawie nie kosztuje czasu renderu, bo praca jest już wykonana — rośnie głównie zużycie pamięci i rozmiar pliku. Po drugie: jeśli warstwy nie sumują się do beauty, to znaczy, że zestaw wzorców czegoś nie pokrywa albo coś liczy dwa razy.
Skoro wzorzec może wymagać konkretnego typu zdarzenia, może też wymagać konkretnego źródła na końcu ścieżki. Tak działają light groups: przypisujesz światłom etykiety, a renderer wystawia osobny bufor na każdą z nich.
Efekt jest taki, że po renderze możesz zmienić intensywność i barwę każdego światła osobno, w compingu, bez ponownego liczenia sceny — bo każde ma własną warstwę, a ich suma to znów beauty. Przy scenie z kilkunastoma światłami zamienia to iterację „popraw, wyrenderuj, obejrzyj” trwającą godziny w suwak działający natychmiast.
Ograniczenie warto znać: tak zrekonstruowana zmiana jest liniowa. Podkręcenie światła w compingu skaluje jego wkład, ale nie zmieni tego, co ono oświetla pośrednio w sposób nieliniowy — nie pojawi się nowy refleks tam, gdzie ścieżek nie było. Do dużych zmian nadal trzeba renderu.
Składnia pochodzi ze specyfikacji Open Shading Language, więc jest zaskakująco zgodna między silnikami — Arnold, RenderMan i inne renderery oparte o OSL rozumieją te same wyrażenia. Standardowe AOV-y, które widzisz na liście (direct_diffuse, indirect_specular, transmission), to gotowe LPE, które ktoś już za Ciebie wpisał; w każdej chwili możesz dopisać własne.
Najczęstsze zastosowanie własnego LPE w lookdevie to izolacja jednego komponentu materiału po to, żeby zobaczyć, co właściwie robi — na przykład sam coat albo samo SSS z Dodatku AG, oddzielone od reszty. To szybsza diagnoza niż wyłączanie komponentów po kolei i renderowanie od nowa.
LPE dzieli obraz według tego, co światło robiło. Dodatek AK rozwiązuje pokrewny problem podziału według tego, w co promień trafił — czyli maski per obiekt.