Come faccio a scrivere uno shader che si illumina quando gli oggetti si trovano vicino a una superficie?


15

In questo video di gioco di Overwatch , lo scudo del personaggio si illumina di bianco nelle aree vicine alla geometria di altri oggetti.

Lo scudo di Reinhart ritaglia una certa geometria di livello

Nota i bordi bianchi sullo scudo blu, vicino al pavimento, alle pareti e al pilastro.

Credo che lo scudo abbia un suo modello e l'effetto sia fatto con uno shader, ma mi sono perso cercando di capire come tradurre il concetto di "vicinanza" alla programmazione dello shader.


2
Se stai usando Unity, questo discorso potrebbe essere interessante . Controlla la sezione "Punti salienti dell'intersezione" a partire dalla diapositiva 26.
DMGregory

Quindi la risposta è già stata trattata di seguito, ma ecco un video che ora lo spiega: youtube.com/watch?v=C6lGEgcHbWc
CobaltHex

Risposte:


28

Uno schema generale:

  1. Crea una mappa di profondità della tua scena senza lo scudo. Puoi ottenerlo in modo efficace gratuitamente, poiché gli oggetti trasparenti sono spesso resi in un passaggio successivo comunque. Altrimenti, è possibile creare la mappa della profondità eseguendo il rendering della scena senza scudo su un RTT con uno shader di profondità.

  2. Rendi la tua scena normalmente, passa la mappa della profondità al tuo shader scudo.

  3. Nello shader, calcola la differenza nella profondità della scena dalla profondità del frammento di scudo e usa quella differenza per modificare il colore del frammento.

dimostrazione

Ho scritto una semplice demo WebGL di questo.

screenshot della demo

Linea per linea

Analizziamo in dettaglio il codice dello shader di frammenti:

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

Campiona la mappa di profondità in ogni frammento. Ricorda di dividere per le dimensioni della finestra per convertire il frammento dallo spazio dello schermo [0, larghezza / altezza] in coordinate [0.0, 1.0] normalizzate. A questo punto, se si imposta semplicemente il colore del frammento sul pixel della mappa di profondità campionato, sarebbe simile al seguente:

screenshot della mappa di profondità

La mappa di profondità è in scala di grigi, quindi puoi ottenere il valore da qualsiasi canale (ho usato rqui).

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

È quindi possibile utilizzare quel campione di profondità per trovare la differenza tra la profondità della scena e la profondità del frammento dello scudo. Ricorda di normalizzare anche la tua profondità, per portarla da [zNear, zFar] (i piani vicino e lontano della tua fotocamera) a [0.0, 1.0]. smoothsteplo fa bene. Il 1.0 -è invertire il valore tale chesolidsDiff è 1,0 quando la differenza è il massimo (zFar - zNear) e 0,0 al minimo (0,0).

Si noti che ho supposto che solidsDepthfosse già normalizzato nello shader di profondità che ha creato la mappa di profondità.

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

È quindi possibile modificare il canale alfa dello scudo in base alla differenza di profondità. Qui iniziamo con un minimo di alfa di 0.3, quindi creiamo un piacevole aumento marcato dell'alfa quando ci avviciniamo alla 0.0differenza.

L' - 0.005offset aggiunge solo un margine bianco per rendere più "incrocio" più spesso. Prova a modificarlo!

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

E infine, applica quell'alfa al colore del tuo frammento.


miglioramenti

Potresti creare uno scudo curvo, aggiungere plasma per un aspetto "scudo di energia" (demo) o esplorare gli effetti con solo le intersezioni che mostrano (demo) .

Il cielo La tua scheda grafica è il limite!


Oh. Mio. Buone notizie. Ty per il fantastico tutorial.
Blue Bug,

5

Sta solo usando la mappa della profondità. Rende il mondo quindi rende lo scudo e prende una differenza tra il valore z renderizzato dello scudo e il valore z del buffer di profondità per tingere il pixel di più bianco.


3

Non so quale motore, se presente, stai utilizzando. O con quale lingua stai lavorando. Tuttavia, la maggior parte di ciò che puoi trovare online non è difficile da trasferire da un ambiente all'altro per ottenere ciò che stai cercando.

E c'è sicuramente del materiale online che può esserti di aiuto. Vedi questa discussione relativa a Unity: http://www.superspacetrooper.com/2012/06/tutorial-force-field-weapon-impact-energy-dispersion/ e questa domanda relativa a UE4: https: //answers.unrealengine. com / questions / 74858 / dynamic-forcefield-shader.html . Per un esempio completo di shader, implementando quell'effetto scudo, da un dibattito abbastanza recente in Reddit, puoi vedere: https://www.reddit.com/r/Unity3D/comments/3edi0n/does_any_one_knows_how_to_make_this_shield_effect/ E per un tutorial che non lo è esattamente su questo, ma è abbastanza correlato a di interesse: http://www.nightbox-studios.com/2015/09/05/assets-shield-effect-scripts-for-texture3d-perlin-noise-shader/

Inoltre, ecco i collegamenti per 3 domande correlate precedentemente fatte in questo stesso sito, che probabilmente saranno di grande aiuto per comprendere i concetti alla base di ciò che si desidera ottenere:

Chiarore dello scudo dell'astronave

Come implementare uno scudo di energia di Starwar in gioco

Effetto scudo XNA con un problema di sfera primitiva

Infine, ci sono alcune belle implementazioni di shader di scudi sia in Unity che in Unreal Engine nel rispettivo negozio virtuale, se ti capita di usare uno di questi motori. Sono generalmente beni pagati ovviamente, ma sono quasi sempre open source dopo l'acquisto - e spesso sono economici. Anche se non ti capita di usare questi motori, queste risorse possono essere di aiuto per giocare e imparare.

Spero che sia d'aiuto.


Sebbene questi collegamenti siano utili, questa risposta è fondamentalmente solo collegamenti e in realtà non affronta direttamente la domanda. Sarebbe meglio estrarre il contenuto pertinente dei collegamenti in una spiegazione effettiva.
Anko,

Sebbene questo collegamento possa rispondere alla domanda, è meglio includere qui le parti essenziali della risposta e fornire il collegamento come riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia. - Dalla recensione
Vaillancourt

@Anko Certo, mio ​​male. Di solito includo una spiegazione e una raccolta di collegamenti, ma questa volta hai ragione, mancava la vera spiegazione. Probabilmente eliminerò la risposta, quindi.
MAnd

@AlexandreVaillancourt Non mi piace l'idea di copiare e incollare da un altro collegamento invece di reindirizzare l'OP alla fonte originale. Quindi, ciò che penso sia meglio è quello di fornire collegamenti nei commenti alla domanda. Il problema con questo è quando si conosce un sacco di materiale che può essere di aiuto ma è troppo grande per i commenti. Ma comunque, poiché una buona risposta esplicativa era già stata pubblicata qui, cancellerò solo questa
MAnd
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.