PROJ · 3 osie (X/Y/Z)BLEND · |N|^kKOSZT · 3–9× odczytówEXT OF · R.9
Dodatek AA / Głębiej: Teksturowanie

Triplanar mapping

Rozdział 9 zakładał, że każdy wierzchołek ma sensowne UV. Terrain wygenerowany proceduralnie, wynik operacji boolean, siatka z voxel meshingu — żadne z nich nie mają UV, które nie byłoby pocięte na strzępy albo rozciągnięte do nieużywalności. Triplanar całkowicie omija UV.

TL;DR
Pass: Problem

Kiedy UV w ogóle nie ma sensu

Cała maszyneria z Rozdziału 9 — interpolacja barycentryczna UV, filtrowanie, mipmapy — zakłada, że ktoś (artysta w edytorze UV albo automatyczny unwrapper) już wcześniej „rozłożył” siatkę na płaski obraz w sposób sensowny: bez rozciągnięć, bez nachodzących na siebie trójkątów, bez szwów w widocznych miejscach. To działa świetnie dla modelowanej ręcznie postaci czy rekwizytu. Zawodzi całkowicie dla geometrii, która nie jest modelowana ręcznie: terrain z generatora szumu, wynik CSG (boolean subtract/union), powierzchnia wyciągnięta z pola voxelowego (marching cubes). Taka geometria zmienia się przy każdej regeneracji — UV policzone raz stają się nieaktualne, a przeliczanie ich w locie, w czasie rzeczywistym, dla zmieniającej się siatki jest zwyczajnie za drogie.

Triplanar mapping odpowiada na to inaczej: zamiast szukać dobrego UV, w ogóle z niego rezygnuje. Teksturuje bezpośrednio na podstawie pozycji punktu w przestrzeni świata — czegoś, co istnieje zawsze, niezależnie od tego, jak bardzo pogięta czy proceduralna jest siatka.

Pass: Algorytm

Trzy projekcje, jedno mieszanie

Algorytm rzutuje tę samą teksturę z trzech kierunków — wzdłuż osi X, Y i Z — traktując dwie pozostałe współrzędne pozycji świata jako zwykłe UV zwykłego, planarnego mapowania z Rozdziału 9:

uv_x = (P.y, P.z)   uv_y = (P.x, P.z)   uv_z = (P.x, P.y)P — pozycja punktu trafienia w przestrzeni świata (albo lokalnej obiektu); każda projekcja używa dwóch z trzech współrzędnych jako zwykłego UV

Trzy próbki tekstury (color_x, color_y, color_z — jedna na projekcję) miesza się wagami opartymi na tym, jak bardzo normalna N w tym punkcie jest zwrócona wzdłuż każdej osi:

w_i = |N_i|^k / (|N_x|^k + |N_y|^k + |N_z|^k)i ∈ {x,y,z}; k — „ostrość” mieszania (zwykle 4–8); wagi sumują się do 1, więc wynik to color = w_x·color_x + w_y·color_y + w_z·color_z
Triplanar.projections3 axes onto a rock
BRYŁA BEZ SENSOWNEGO UV rzut wzdłuż X → uv=(P.y,P.z) rzut wzdłuż Y → uv=(P.x,P.z) rzut wzdłuż Z → uv=(P.x,P.y)
Trzy niezależne, zwykłe planarne mapowania — jedyna „magia” jest w tym, jak się je miesza.
Policzone: wagi dla konkretnej normalnej
Normalna w punkcie: N = (0,333, 0,667, 0,667) (znormalizowana: 1,2,2 podzielone przez 3)
k = 4: |N_x|⁴ = 0,333⁴ = 0,0123; |N_y|⁴ = |N_z|⁴ = 0,667⁴ = 0,1979
Suma = 0,0123 + 0,1979 + 0,1979 = 0,4081
w_x = 0,0123 / 0,4081 ≈ 3%   w_y = w_z ≈ 48,5%
Ta sama normalna z k=1 (bez ostrzenia) dałaby w_x=20%, w_y=w_z=40% — dużo bardziej rozmyte mieszanie wszystkich trzech, mniej widoczny szew, ale i mniej wyrazista tekstura w każdym miejscu.

Rezultat: projekcja X przy tej normalnej wnosi tylko 3% końcowego koloru — normalna prawie nie wskazuje wzdłuż X, więc ta projekcja i tak byłaby mocno „rozciągnięta” (patrzysz na powierzchnię niemal stycznie do niej). Wyższe k robi z tego niemal zero, ostrzej wybierając dominującą oś.

Pass: Szwy

Gdzie mieszanie 50/50 psuje obraz

Tam, gdzie normalna leży dokładnie między dwiema osiami (krawędź skały pod 45°, gdzie N wskazuje jednakowo wzdłuż dwóch kierunków), dwie projekcje mieszają się mniej więcej po połowie. Problem: to dwie niezależne próbki tego samego wzoru tekstury, w różnej orientacji i przesunięciu — ich nałożenie nie daje spójnego wzoru, tylko widoczne, „podwójne” rozmycie, jakby dwie różne tekstury prześwitywały jedna przez drugą.

Seam.blend.zonek=1 vs k=8
k = 1 (miękkie) k = 8 (ostre) szeroka strefa mieszania, mniej widoczny szew wąska, ostrzejsza granica
Wyższe k nie usuwa szwu — ścieśnia go do węższego pasa, kosztem bardziej widocznej granicy w tym pasie.

Nie ma darmowego wyjścia: mniejsze k rozmywa szew na szerszym obszarze (mniej widoczny, ale tekstura w tym obszarze wygląda „papkowato”), większe k ścieśnia go do wąskiego pasa (reszta powierzchni czysta, ale w tym pasie granica jest bardziej gwałtowna). Produkcyjne wartości k mieszczą się zwykle między 4 a 8 — kompromis wypracowany empirycznie, nie z żadnego wzoru.

Pass: Warianty

Biplanar i normal mapping

Biplanar mapping to optymalizacja: skoro projekcja z najmniejszą wagą i tak wnosi niewiele (3% w przykładzie wyżej), po co ją w ogóle liczyć? Biplanar dynamicznie wybiera dwie projekcje o największych wagach (odrzucając oś, wzdłuż której normalna wskazuje najsłabiej) i miesza tylko je, renormalizując wagi do sumy 1. Oszczędza jeden odczyt tekstury na trzy — kosztem widocznego, choć zwykle drobnego, przeskoku w miejscu, gdzie zmienia się, która oś jest odrzucana.

Normal mapping w triplanarze to osobny, częściej pomijany problem: każda z trzech projekcji patrzy z innego kierunku, więc normal mapa odczytana z tekstury (zawsze zdefiniowana w lokalnej przestrzeni stycznej tej projekcji) musi zostać obrócona tak, żeby pasowała do rzeczywistej orientacji powierzchni w tym miejscu, nie do sztucznego układu współrzędnych projekcji. Pominięcie tego kroku daje efekt „wgnieceń w złą stronę” dokładnie w strefach mieszania między projekcjami — działa poprawnie tylko tam, gdzie jedna projekcja dominuje w 100%.

Pass: Koszt

Realna cena: policzone na przykładzie materiału

Typowy materiał metallic-roughness ma trzy mapy: Base Color, ORM (occlusion/roughness/metallic spakowane w jeden obraz) i Normal. Ze zwykłym UV to trzy odczyty tekstury na trafienie. Pełny triplanar (trzy projekcje) mnoży to razy trzy:

UV zwykłe: 3 mapy × 1 projekcja = 3 odczyty   Triplanar: 3 mapy × 3 projekcje = 9 odczytówkażdy „odczyt” to już przefiltrowana próbka z Dodatku G (trójliniowa/anizotropowa/EWA) — triplanar mnoży też ten koszt filtrowania razy trzy, nie tylko surowy odczyt tekstury

Biplanar sprowadza to do 6 odczytów zamiast 9 — wciąż dwa razy drożej niż UV, ale zauważalnie taniej niż pełny triplanar. W scenach, gdzie tylko część geometrii (terrain, wygenerowane skały) potrzebuje triplanaru, a reszta ma normalne UV, koszt jest lokalny — płacisz go tylko tam, gdzie faktycznie musisz.

Z praktyki

„Triplanar Mapping” w Blenderze (node w Shader Editorze), „World Aligned Texture” w Unrealu i podobne węzły w Houdinim czy Substance Designerze to dosłownie ten algorytm — parametr „Blend” albo „Blend Sharpness” w tych node’ach to k z tego dodatku. Terrain w grach i VFX niemal zawsze używa triplanaru właśnie dlatego, że jest generowany proceduralnie i nigdy nie miałby stabilnego UV.

Słowniczek
Triplanar mapping
Teksturowanie z trzech projekcji (X/Y/Z) na podstawie pozycji świata, bez UV.
Waga mieszania
|N_i|^k znormalizowane do sumy 1 — decyduje, ile każda projekcja wnosi do koloru końcowego.
k (ostrość mieszania)
Wykładnik kontrolujący, jak gwałtownie dominuje projekcja najlepiej dopasowana do normalnej.
Biplanar mapping
Triplanar z pominięciem projekcji o najmniejszej wadze — 2 odczyty zamiast 3.
Szew triplanaru
Widoczne podwójne rozmycie tam, gdzie dwie projekcje mieszają się mniej więcej po równo.