BSSRDF · 2 punktyσt = σs + σaMFP · 1/σtEXT OF · R.18, R.10
Dodatek AG / Lookdev w praktyce

Subsurface scattering: dlaczego skóra nie jest matowa

Rozdział 10 nazwał diffuse „światłem, które wniknęło pod powierzchnię i wyszło w losowym kierunku” — i od razu założył, że wyszło w tym samym punkcie. Dla betonu to prawda z dokładnością do mikrometrów. Dla skóry, wosku, marmuru i mleka to założenie jest fałszywe i widać to gołym okiem. Ten dodatek pokazuje, co dokładnie się psuje, jak renderer to naprawia i którym pokrętłem naprawdę sterujesz.

TL;DR
Pass: Dwa punkty zamiast jednego

Co dokładnie psuje się w BRDF

BRDF z Rozdziałów 10–11 to funkcja f(p, ω_i, ω_o): jeden punkt p, kierunek wejścia, kierunek wyjścia. Cztery wymiary, bo każdy kierunek to dwa kąty. Cała jej konstrukcja opiera się na założeniu, że światło wchodzi i wychodzi w tym samym miejscu.

SSS łamie dokładnie to założenie, więc potrzebuje funkcji o dwóch punktach — S(x_i, ω_i; x_o, ω_o), zwanej BSSRDF. Osiem wymiarów zamiast czterech: dwa punkty na powierzchni po dwie współrzędne i dwa kierunki po dwa kąty.

L_o(x_o, ω_o) = ∫_A ∫_Ω S(x_i, ω_i; x_o, ω_o) · L_i(x_i, ω_i) · (N·ω_i) dω_i dARóżnica względem równania renderowania z Rozdziału 15 to dodatkowa całka po powierzchni A: żeby policzyć światło wychodzące w x_o, trzeba zebrać wkład ze wszystkich punktów x_i, w których cokolwiek mogło wniknąć. BRDF to szczególny przypadek, w którym S jest niezerowe tylko dla x_i = x_o

Ta dodatkowa całka po powierzchni jest całym kosztem i całym efektem. To ona sprawia, że ucho podświetlone od tyłu świeci na czerwono, a nos w zbliżeniu ma miękkie, „mięsiste” przejście do cienia zamiast twardej krawędzi Lamberta.

Kiedy można to zignorować. Jeśli typowe przesunięcie między wejściem a wyjściem jest wyraźnie mniejsze niż piksel, całka po A zbiega się do jednego punktu i BSSRDF staje się BRDF — nie przez przybliżenie, tylko dokładnie. Dlatego ta sama postać w szerokim planie nie potrzebuje SSS, a w zbliżeniu na twarz potrzebuje go rozpaczliwie. To nie jest kwestia „jakości ustawień”, tylko relacji między promieniem rozpraszania a wielkością piksela w tym konkretnym ujęciu.

Pass: Ośrodek

Trzy liczby opisujące materiał

Rozdział 18 wprowadził σ_t jako jeden współczynnik ekstynkcji w prawie Beera-Lamberta. Pod powierzchnią trzeba go rozbić, bo światło ginie z wiązki na dwa zupełnie różne sposoby: albo zostaje pochłonięte (zamienione w ciepło, przepada), albo rozproszone (leci dalej, tylko w innym kierunku).

σ_t = σ_s + σ_a
α = σ_s / σ_tσ_s — rozpraszanie, σ_a — absorpcja, oba w jednostkach 1/długość. α (albedo pojedynczego rozproszenia) mówi, jaka część zdarzeń to rozproszenie, a nie pochłonięcie. Materiały SSS mają α bardzo blisko 1 — światło odbija się w środku setki razy, zanim cokolwiek je pochłonie
MFP = 1 / σ_tŚrednia droga swobodna (mean free path) — dystans, jaki foton przebywa średnio między dwoma zdarzeniami. To jest ta „długość”, którą w interfejsie widzisz jako radius albo mean free path, i to ona decyduje, jak daleko światło rozlewa się pod skórą

Do kompletu dochodzi czwarta wielkość, którą znasz już z Rozdziału 18: anizotropia g funkcji fazowej. Tkanki biologiczne rozpraszają silnie do przodu (g rzędu 0,7–0,9), a nie równomiernie — foton po rozproszeniu leci mniej więcej tam, gdzie leciał.

↓ Dodatek Z — funkcja fazowa Henyeya-Greensteina i parametr g
Pass: Dwie szkoły

Dyfuzja kontra random walk

Mając te współczynniki, renderer może pójść dwiema drogami. Różnica między nimi to najważniejszy przełącznik w całym shaderze SSS.

Aproksymacja dyfuzyjna. Skoro α ≈ 1 i rozproszeń są setki, to statystycznie światło zachowuje się jak dyfuzja — rozlewa się od punktu wejścia według gładkiego profilu, którym można opisać całą chmurę ścieżek jednym wzorem. Renderer nie śledzi niczego pod powierzchnią; oświetla powierzchnię, a potem rozmywa to oświetlenie profilem R(r) zależnym wyłącznie od odległości między punktami.

Random walk. Renderer po prostu robi to, co Rozdział 18 robił we mgle: załamuje promień do wnętrza, losuje dystans do następnego zdarzenia z rozkładu wykładniczego, rozprasza kierunek funkcją fazową, powtarza — aż foton zostanie pochłonięty albo wyjdzie przez powierzchnię. Żadnego profilu, żadnego założenia. Ta sama pętla co w wolumetrii, tylko w skali milimetrów.

Diffusion.vs.randomwalkprofil kontra sledzenie
DYFUZJA · jeden profil RANDOM WALK · prawdziwe scieżki R(r) nic nie jest sledzone — powierzchnia jest rozmywana pochłonięty ta sama pętla co w mgle z Rozdziału 18, w skali mm
Dyfuzja zgaduje wynik setek rozproszeń jednym wzorem. Random walk je wykonuje. Przy grubej geometrii oba dają ten sam obraz — różnice zaczynają się tam, gdzie założenie „setek rozproszeń” przestaje być prawdziwe.

Gdzie dyfuzja się rozpada. Jej wyprowadzenie zakłada, że foton ma miejsce na wiele rozproszeń, zanim trafi na powierzchnię. W uchu, płetwie, płatku kwiatu albo skrzydle owada geometria jest cieńsza niż kilka średnich dróg swobodnych — foton wychodzi po dwóch, trzech zdarzeniach. Model dyfuzyjny tego nie przewiduje: cienkie miejsca wychodzą za ciemne i za mało prześwitujące, bo profil zakłada materiał półnieskończony i nie ma pojęcia, że po drugiej stronie jest powietrze. Random walk trafia to poprawnie bez żadnego dodatkowego ustawienia, bo po prostu widzi, że promień wyszedł drugą stroną.

To jest powód, dla którego produkcja przeszła na random walk mimo wyższego kosztu — nie dlatego, że dyfuzja jest „niedokładna” w ogólności, tylko dlatego, że zawodzi dokładnie tam, gdzie patrzy widz: na uszach i nosie w kontrze.

Pass: Pokrętła

Cztery parametry, którymi naprawdę sterujesz

1. Promień per kanał RGB. To nie jest „kolor SSS” w sensie barwnika — to trzy różne odległości. Czerwone światło wnika w tkankę znacznie głębiej niż niebieskie, bo hemoglobina i melanina pochłaniają krótkie fale dużo silniej. Stąd charakterystyczna czerwona poświata na krawędziach: w miejscu, gdzie zieleń i błękit już dawno zostały pochłonięte, czerwień wciąż ma dość energii, żeby wyjść.

Profile.per.channelR(r) dla trzech promieni
0 1 0 1× promień 2× odległość od punktu wejścia R G B
Prawdziwy kształt profilu Burleya dla promieni w proporcji 1,0 / 0,2 / 0,1. Przy odległości „1× promień” czerwień ma jeszcze wyraźny wkład, zieleń resztkowy, a błękit praktycznie zerowy — i to jest cała przyczyna czerwonej poświaty.

2. Skala. Tu ginie najwięcej czasu. Promień jest wyrażony w jednostkach sceny. Ta sama wartość 1,0 znaczy „jeden centymetr” w scenie modelowanej w centymetrach i „jeden metr” w scenie modelowanej w metrach — czyli sto razy więcej rozlania. Postać zaimportowana z innego pipeline'u albo przeskalowana węzłem transformacji potrafi z dnia na dzień zmienić się z realistycznej skóry w półprzezroczysty wosk, przy nietkniętym shaderze.

Scale.trapten sam shader, dwie skale sceny
MODEL W cm · radius 1,0 TEN SAM MODEL W m · radius 1,0 rozlanie ≈ 1 cm — skóra rozlanie ≈ 1 m — cała głowa świeci
Shader identyczny, wartości identyczne, zmieniona wyłącznie jednostka sceny. Dlatego przed strojeniem SSS zawsze sprawdza się, ile jednostek ma model — nie zaczyna się od kręcenia kolorem.

Dlatego shadery rozdzielają zwykle promień (proporcje między kanałami, czyli charakter materiału) od skali (jeden mnożnik dopasowujący całość do jednostek sceny). Charakter skóry stroisz proporcją kanałów; dopasowanie do modelu — mnożnikiem.

3. Współczynnik załamania (IOR). Steruje dwiema rzeczami naraz: siłą odbicia lustrzanego na powierzchni, przez Fresnela z Rozdziału 7, oraz — w random walku — załamaniem promienia przy wejściu do ośrodka. Dla tkanek to okolice 1,33–1,4. Podniesienie IOR rozjaśnia specular i jednocześnie zmienia rozkład światła w środku, więc nie jest to pokrętło „tylko od połysku”.

4. Anizotropia g. Domyślne zero (rozpraszanie izotropowe) jest wygodne, bo pozwala renderowi używać krótszych ścieżek, ale tkanki rozpraszają do przodu. Dodatnie g sprawia, że światło wnika głębiej przy tej samej wartości σ_s — efekt bywa mylony ze zwiększeniem promienia.

Z praktyki

W Arnoldzie to grupa Subsurface w standard_surface: subsurface (waga), subsurface_color, subsurface_radius (trzy kanały), subsurface_scale (mnożnik do jednostek sceny), subsurface_anisotropy oraz przełącznik subsurface_type — randomwalk kontra starsza diffusion. RenderMan wystawia kilka modeli w PxrSurface, w tym ścieżkę path-traced odpowiadającą random walkowi. Karma i inne silniki oparte o MaterialX robią to przez subsurface w MaterialX Standard Surface — czyli ten sam model, który Rozdział 11 opisał jako standard.

Kolejność strojenia, która oszczędza najwięcej czasu: najpierw sprawdź jednostki sceny i ustaw skalę, potem proporcje kanałów, dopiero na końcu wagę i kolor. Odwrotna kolejność kończy się kompensowaniem błędu skali kolorem — i shaderem, który rozjeżdża się przy pierwszym ujęciu z inną kamerą.

Jeśli SSS zaszumia się bardziej niż reszta obrazu, to zwykle random walk na materiale o α bardzo blisko 1: fotony wykonują setki odbić, zanim wyjdą. Renderery mają na to osobne limity kroków i to je podnosi się w pierwszej kolejności, a nie globalną liczbę próbek z Rozdziału 8.

Słowniczek
BSSRDF
Funkcja odbicia z dwoma punktami powierzchni (wejście i wyjście); uogólnienie BRDF na SSS.
σ_s, σ_a, σ_t
Współczynniki rozpraszania, absorpcji i ich suma (ekstynkcja), w jednostkach 1/długość.
Albedo pojedynczego rozproszenia (α)
σ_s/σ_t — jaka część zdarzeń to rozproszenie, nie pochłonięcie. Materiały SSS mają α bliskie 1.
Średnia droga swobodna (MFP)
1/σ_t — średni dystans między zdarzeniami; to, co interfejs nazywa promieniem.
Aproksymacja dyfuzyjna
Zastąpienie setek rozproszeń gładkim profilem R(r); szybka, zawodzi na cienkiej geometrii.
Random walk
Faktyczne śledzenie fotonu wewnątrz ośrodka; fizyczne, poprawne dla cienkich kształtów, droższe.
Idź głębiej
Dodatek Z — Funkcja fazowa Henyeya-Greensteina Dodatek T — Radiometria: czym naprawdę jest „L”