Jak napisać moduł cieniujący, który zapala się, gdy obiekty znajdują się w pobliżu powierzchni?

15

W tym filmie z gry Overwatch tarcza postaci świeci na biało w obszarach znajdujących się w pobliżu geometrii innych obiektów.

Tarcza Reinharta przycina pewną geometrię poziomu

Zwróć uwagę na białe krawędzie niebieskiej tarczy, w pobliżu podłogi, ścian i filaru.

Wierzę, że tarcza ma swój własny model, a efekt jest uzyskiwany za pomocą shadera, ale zgubiłem się, próbując zrozumieć, jak przełożyć pojęcie „bliskości” na programowanie shadera.

Blue Bug
źródło
2
Jeśli używasz Unity, ta rozmowa może być interesująca . Sprawdź sekcję „
Najciekawsze
Więc odpowiedź została już
omówiona

Odpowiedzi:

28

Ogólny zarys:

  1. Utwórz mapę głębi swojej sceny bez tarczy. Możesz uzyskać to skutecznie za darmo, ponieważ obiekty przezroczyste są często renderowane w późniejszym przebiegu. W przeciwnym razie możesz utworzyć mapę głębokości, renderując scenę bez osłony na RTT z shaderem głębokości.

  2. Renderuj scenę normalnie, przekaż mapę głębi do shadera tarcz.

  3. W module cieniującym oblicz różnicę głębokości sceny od głębokości fragmentu osłony i użyj tej różnicy, aby zmodyfikować kolor fragmentu.

Próbny

Napisałem prostą wersję demo tego WebGL.

zrzut ekranu pokazu

Linia po linii

Omówmy szczegółowo kod modułu do cieniowania fragmentów:

float solidsDepth = texture2D(depthMap, gl_FragCoord.xy / dims).r;

Próbkuj mapę głębokości dla każdego fragmentu. Pamiętaj, aby podzielić przez wymiary rzutni, aby przekonwertować fragment z przestrzeni ekranu [0, szerokość / wysokość] na znormalizowane współrzędne [0,0, 1,0]. W tym momencie, jeśli po prostu ustawisz kolor fragmentu na próbkowany piksel mapy głębi, wyglądałoby to tak:

zrzut ekranu mapy głębokości

Mapa głębokości jest w skali szarości, więc możesz uzyskać wartość z dowolnego kanału (użyłem rtutaj).

float solidsDiff = 1.0 - smoothstep(
    zNear,
    zFar,
    gl_FragCoord.z / gl_FragCoord.w
  ) - solidsDepth;

Następnie możesz użyć tej próbki głębokości, aby znaleźć różnicę między głębokością sceny a głębokością fragmentu tarczy. Pamiętaj również o normalizacji głębi, aby przenieść ją z [zNear, zFar] (bliskie i dalekie płaszczyzny aparatu) do [0,0, 1,0]. smoothsteprobi to ładnie. Ma 1.0 -to na celu odwrócenie wartości, która solidsDiffwynosi 1,0, gdy różnica jest wartością maksymalną (zFar - zNear), a wartością minimalną 0,0 (0,0).

Zauważ, że założyłem, że solidsDepthzostał już znormalizowany w module cieniującym, który utworzył mapę głębokości.

float alpha = 0.3 + max(0.0, 1.0 - log(100.0 * (solidsDiff - 0.005) + 1.0));

Następnie możesz zmodyfikować kanał alfa swojej tarczy w zależności od różnicy głębokości. Tutaj zaczynamy od minimalnej wartości alfa 0.3, a następnie tworzymy ładny gwałtowny wzrost alfa, gdy zbliżamy się do 0.0różnicy.

- 0.005Przesunięcie tylko dodaje biały margines, aby „skrzyżowanie” grubsze. Spróbuj to zmodyfikować!

gl_FragColor = vec4(vec3(1.0), alpha);

Na koniec zastosuj tę alfa do koloru fragmentu.


Ulepszenia

Możesz zrobić zakrzywioną tarczę, dodać plazmę, aby uzyskać wygląd „tarczy energetycznej” (demo) lub eksplorować efekty za pomocą tylko pokazanych skrzyżowań (demo) .

Niebo Twoja karta graficzna to limit!

Yousef Amar
źródło
O. Mój. Dobre wieści. Ty za niesamowity samouczek.
Blue Bug
5

Po prostu używa mapy głębokości. Renderuje świat, a następnie renderuje tarczę i przyjmuje różnicę między renderowaną wartością z osłony a wartością z bufora głębokości, aby zabarwić piksel bardziej biały.

Syryjski
źródło
3

Nie wiem, jakiego silnika używasz. Lub w jakim języku pracujesz. Jednak większość tego, co można znaleźć w Internecie, nie jest trudna do przeniesienia z jednego środowiska do drugiego, aby osiągnąć to, czego szukasz.

I z pewnością jest materiał online, który może ci pomóc. Zobacz tę dyskusję związaną z Unity: http://www.superspacetrooper.com/2012/06/tutorial-force-field-weapon-impact-energy-dispersion/ oraz to pytanie związane z UE4: https: //answers.unrealengine. com / pytania / 74858 / dynamic-forcefield-shader.html . Aby uzyskać pełny przykład modułu cieniującego, implementującego ten efekt tarczy, z dość niedawnej debaty w Reddit, możesz zobaczyć: https://www.reddit.com/r/Unity3D/comments/3edi0n/does_any_one_knows_how_to_make_this_shield_effect/ I samouczek, który nie jest dokładnie na tym, ale jest wystarczająco związany z zainteresowaniem: http://www.nightbox-studios.com/2015/09/05/assets-shield-effect-scripts-for-texture3d-perlin-noise-shader/

Oto również linki do 3 powiązanych pytań zadanych wcześniej na tej stronie, które mogą być bardzo pomocne w zrozumieniu koncepcji stojących za tym, co chcesz osiągnąć:

Flara tarczy statku kosmicznego

Jak zaimplementować w grze tarczę energii gwiezdnej wojny

Efekt osłony XNA z problemem sfery pierwotnej

Na koniec istnieje całkiem sporo fajnych implementacji shaderów tarcz zarówno w Unity, jak i Unreal Engine w ich odpowiednich sklepach wirtualnych, jeśli używasz któregoś z tych silników. Są to zazwyczaj aktywa płatne, ale po zakupie prawie zawsze są open source - i często są tanie. Nawet jeśli nie używasz tych silników, te zasoby mogą pomóc w zabawie i nauce.

Mam nadzieję, że to pomoże.

MAnd
źródło
Chociaż te linki są pomocne, ta odpowiedź jest w zasadzie tylko linkami i nie odnosi się bezpośrednio do pytania. Lepiej byłoby wyodrębnić odpowiednią treść linków w rzeczywiste wyjaśnienie.
Anko,
Chociaż ten link może odpowiedzieć na pytanie, lepiej dołączyć tutaj istotne części odpowiedzi i podać link w celach informacyjnych. Odpowiedzi zawierające tylko łącze mogą stać się nieprawidłowe, jeśli zmieni się połączona strona. - Z recenzji
Vaillancourt
@Anko Pewnie, mój zły. Zwykle dołączam wyjaśnienie i zbiór linków, ale tym razem masz rację, brakowało prawdziwego wyjaśnienia. W takim razie prawdopodobnie usunę odpowiedź.
MA
@AlexandreVaillancourt Nie podoba mi się pomysł kopiowania i wklejania z innego linku zamiast przekierowywania OP do oryginalnego źródła. Następnie myślę, że najlepiej jest podać linki w komentarzach do pytania. Problem polega na tym, że wiesz dużo materiału, który może być pomocny, ale jest zbyt duży, by komentować. Ale wciąż, ponieważ dobre wyjaśnienie zostało już tutaj opublikowane, po prostu
skasuję