PROBLEM · ID nie da się filtrowaćHASH · nazwa → float32PARY · (id, pokrycie)EXT OF · R.19, R.8
Dodatek AK / Warstwa wyjścia

Cryptomatte: maski, których nie da się uśrednić

Wydzielenie jednego obiektu w compingu wygląda na najprostszą rzecz pod słońcem: nadaj każdemu obiektowi numer, zapisz numery do bufora, gotowe. Ten dodatek pokazuje, dlaczego to nie działa — i to nie z powodu implementacji, tylko z powodu antyaliasingu z Rozdziału 8.

TL;DR
Pass: Problem

Dlaczego zwykły ID pass zawodzi

Rozdział 8 ustalił, że piksel na krawędzi obiektu nie należy do żadnego z nich w całości — kilka podpróbek trafia w jeden obiekt, kilka w drugi, a wynik jest ich średnią. Dla koloru to jest dokładnie to, czego chcemy: gładka krawędź.

Dla identyfikatora to katastrofa. Numer obiektu jest etykietą, nie wielkością — nie ma czegoś takiego jak „obiekt pomiędzy”. Uśrednienie ID 3 i ID 7 z wagami pół na pół daje 5, czyli wskazuje na zupełnie inny obiekt sceny. Im ładniejszy antyaliasing, tym gorsze maski.

ID.averaging.failskrawedz miedzy dwoma obiektami
PIKSEL NA KRAWĘDZI ID 3 ID 7 60% / 40% 0,6 · 3  +  0,4 · 7  =  5 obiekt nr 5 nie ma z tym pikselem nic wspólnego potrzebna lista, nie liczba: (3 → 0,6)   (7 → 0,4)
Nie ma takiej wartości, którą dałoby się zapisać w jednym kanale, żeby uczciwie opisać „w 60% obiekt 3, w 40% obiekt 7”. Rozwiązaniem nie jest lepsza liczba, tylko inna struktura danych.

Historyczne obejścia sprowadzały się do rezygnacji z antyaliasingu w ID passie: jedna próbka na piksel, twarde krawędzie, ręczne dopasowywanie masek. Działało średnio, a przy motion blurze i głębi ostrości przestawało działać w ogóle — tam „krawędzią” jest cała rozmyta smuga, nie jedna linia.

Pass: Rozwiązanie

Lista par zamiast jednej liczby

Cryptomatte zapisuje dla każdego piksela to, co renderer faktycznie zaobserwował: które obiekty go pokryły i w jakim ułamku. Nic nie jest uśredniane między identyfikatorami — sumowane są tylko pokrycia, każde przy swoim identyfikatorze.

piksel → [ (id₁, w₁), (id₂, w₂), (id₃, w₃), … ]   Σ wᵢ = 1idᵢ — identyfikator obiektu albo materiału; wᵢ — jego udział w pikselu, czyli dokładnie to pokrycie podpikselowe, które Rozdział 8 liczył dla koloru. Pary są sortowane malejąco po wadze, a lista przycinana do kilku pierwszych — reszta wnosi tak mało, że nie zmienia maski

Identyfikator nie jest kolejnym numerem, tylko skrótem nazwy. Renderer bierze nazwę obiektu albo materiału, przepuszcza ją przez funkcję haszującą i zapisuje wynik jako liczbę zmiennoprzecinkową. Ma to dwie zalety: nie trzeba prowadzić żadnej centralnej numeracji, a maska przetrwa przenumerowanie sceny — dopóki nazwa się nie zmieni, skrót jest ten sam.

Odwzorowanie skrótów na czytelne nazwy ląduje w metadanych pliku, więc program do compingu może pokazać listę obiektów zamiast liczb. To dlatego wybierasz obiekt, klikając w niego w obrazie: kliknięcie odczytuje skrót spod kursora i szuka go w tej tablicy.

Cryptomatte.layerspary upakowane w kanaly
JEDNA WARSTWA RGBA = DWIE PARY R = id₁ G = w₁ B = id₂ A = w₂ R = id₃ G = w₃ B = id₄ A = w₄ warstwa 00 warstwa 01 więcej warstw = więcej obiektów na piksel dwie warstwy wystarczają w większości ujęć; futro i liście potrzebują więcej
Pary upakowane po dwie w czterokanalową warstwę. Liczba warstw to jedyne ustawienie, którym realnie sterujesz — decyduje, ile różnych obiektów może współdzielić jeden piksel, zanim najsłabsze zostaną odrzucone.
Pass: Konsekwencje

Dlaczego motion blur i włosy działają same z siebie

Najładniejsza cecha tego rozwiązania jest taka, że nie wymagało niczego dodatkowego dla trudnych przypadków. Waga to zwykłe pokrycie podpikselowe — a wszystko, co renderer już robi przez próbkowanie, wpływa na nie automatycznie:

Ograniczenie warto znać: to jest maska pokrycia, nie maska oświetlenia. Cryptomatte powie Ci, gdzie obiekt jest widoczny, ale nie oddzieli światła, które on rzuca na innych — od tego jest LPE z Dodatku AJ. Te dwa mechanizmy odpowiadają na dwa różne pytania i w praktyce używa się ich razem.

Z praktyki

Cryptomatte jest otwartym standardem, nie funkcją jednego silnika — Arnold, RenderMan, Karma, V-Ray i Cycles zapisują ten sam format, a Nuke, Fusion i After Effects go czytają. Renderery wystawiają zwykle trzy warianty naraz: po obiekcie, po materiale i po nazwie węzła — bo w compingu raz potrzebujesz „ten konkretny model”, a raz „wszystko, co ma ten shader”.

Typowy objaw za małej liczby warstw: maska wygląda dobrze na płaskich powierzchniach, ale gubi się na futrze albo w listowiu, zostawiając dziury. To nie jest błąd wyboru w compingu, tylko informacja, że najsłabsze udziały zostały przycięte przy zapisie — i naprawia się to po stronie renderu, nie kompozycji.

Słowniczek
Cryptomatte
Otwarty format masek zapisujący per piksel listę par (identyfikator, pokrycie).
Skrót nazwy (hash)
Nazwa obiektu przepuszczona przez funkcję haszującą i zapisana jako liczba zmiennoprzecinkowa.
Pokrycie (coverage)
Udział obiektu w pikselu; to samo pokrycie podpikselowe co przy antyaliasingu z Rozdziału 8.
Manifest
Tablica skrót → nazwa zapisana w metadanych pliku; pozwala pokazać nazwy zamiast liczb.
Idź głębiej
Dodatek D — Mechanika denoisera