Come posso rendere l'acqua più scura con la profondità, come in Minecraft?


24

In Minecraft quando guardi l'acqua più in profondità vedi più diventa scuro. Qualcuno sa come codificare qualcosa del genere?

Minecraft con effetto minecraft con effetto

gioco simile senza effetto gioco simile senza effetto


18
Questo non è fatto automagicamente poiché il materiale del cubo d'acqua è semi-trasparente?
pek

Io non la penso così. Ho aggiunto un'immagine senza l'effetto per il confronto.
Xavier,

2
Forse è un effetto di miscela additiva applicato solo sui cubetti d'acqua? Ancora una volta, questo dovrebbe essere facile poiché il materiale è semi-trasparente.
pek

1
puoi anche cambiare il colore delle scatole in base alla profondità.
Ali1S232,

Risposte:


51

Esistono essenzialmente due approcci diversi per l'illuminazione dell'acqua in base alla profondità:

Voxel-Lighting

Minecraft utilizza l'illuminazione basata su voxel, che funziona propagando la luce in cubi adiacenti, riducendo la luminosità in base al tipo di blocco. Gli oceani scuri sono un effetto collaterale di questo sistema.

L'acqua blocca la luce solare e riduce la luce di 3 livelli per blocco (anziché il livello predefinito 1), il che significa che la luminosità in un oceano per ogni distanza dalla superficie è:

0 (surface): 15 (direct sunlight)
1:           12
2:            9
3:            6
4:            3
5 and below:  0 (darkness)

Fonte: Minecraft Wiki - Light

Ombreggiamento basato sulla distanza

Nei giochi con un modello di illuminazione tradizionale, questo effetto può essere creato misurando la quantità di acqua che si trova tra la sorgente luminosa e il fondo dell'oceano. La luce viene quindi sbiadita in base a questa distanza. Esistono alcuni metodi per farlo:

Calcolo diretto

Se hai una superficie piana, puoi facilmente calcolare la distanza che la luce percorre nell'acqua se passi la superficie normale lontano dal corpo idrico \ Vec {n}e il prodotto punto di questa normale e una posizione della superficie Snello shader della geometria.

La distanza effettiva dell'acqua è

\ max (\ left (s - \ vec {n} \ cdot \ vec {p} \ right), 0) \ cdot \ left (1 + \ tan (\ alpha) \ right)

dov'è \ Vec {p}la posizione del vertice ed alfaè l'angolo tra la direzione della luce sotto la superficie e la superficie dell'acqua normale verso il corpo idrico.

Al tramonto, alfaraggiunge solo un po 'meno di 50 ° perché la luce viene rifratta quando si entra nell'acqua.
Ecco un post sul blog con una buona spiegazione: la fotocamera digitale: riflessione interna totale
Un altro post con maggiori dettagli: la fotocamera digitale: la legge di rifrazione di Snell

Se stai usando una mappa di altezza su una superficie parallela all'acqua, \ left (s - \ vec {n} \ cdot \ vec {p} \ right)diventa \ left (s - h \ right). Il fattore giusto equivale a 1 se il sole è direttamente sopra la superficie dell'acqua.
Con una luce puntiforme, devi calcolare alfaper ciascun vertice in base alla posizione relativa alla sorgente luminosa.

Con un livello dell'acqua fisso o una direzione della luce fissa, parti dell'equazione sono costanti e non dovrebbero essere calcolate nello shader per motivi di prestazioni.

Professionisti:

  • Veloce e preciso

Contro:

  • Funziona solo per superfici d'acqua piatte o solo per la luce proveniente direttamente dall'alto, poiché di solito viene presa in considerazione solo una superficie. (La combinazione di una superficie ruvida e una luce inclinata potrebbe funzionare in qualche modo con la mappatura della parallasse.)
  • Nessuna caustica

Shadow Mapping

Se si esegue il rendering della superficie dell'acqua su una mappa di profondità separata (vista dalla sorgente luminosa), è possibile utilizzare quella trama di profondità per calcolare la distanza che la luce percorre nell'acqua prima di colpire la superficie.
Per fare ciò, proietti ciascun vertice nella proiezione della vista della sorgente luminosa nello shader di vertice ed esegui la ricerca della trama nel pixel shader.

Se la superficie è relativamente piatta, è necessario utilizzare un'origine di luce rifratta per risultati migliori.

Professionisti:

  • Funziona con geometria dell'acqua relativamente complessa, purché non si occluda da sola. *
  • Può essere riutilizzato per quasi ogni tipo di volume parzialmente trasparente.

Contro:

  • Più lento del calcolo diretto.
  • Richiede VRAM aggiuntiva per la mappa di profondità.
  • Non preciso al 100%.

* È possibile determinare la quantità di acqua davanti alla superficie solida più vicina contando la profondità dal POV della luce come segue:

  1. Rendering normale della geometria solida nella scena. Per ogni frammento, aggiungi il valore della profondità alla trama del risultato.
  2. Rendering delle facce frontali dell'acqua senza aggiornare il buffer di profondità e sottrarre le profondità dei frammenti dal risultato.
  3. Rendi le facce posteriori allo stesso modo, ma aggiungi la profondità del frammento al risultato.

La trama del risultato ora contiene la quantità di acqua davanti alla luce nello spazio della vista della luce, quindi il valore deve essere trasformato indietro prima di usarlo. Questo metodo funziona per calcolare la luce direzionale (meno la rifrazione), ma porterà a una luce ambientale errata se le superfici sono molto irregolari e c'è una grande quantità di aria tra i corpi idrici che colpiscono gli stessi frammenti.
I pro e i contro sono gli stessi della normale mappatura dell'ombra, tranne per il fatto che è necessario un altro buffer durante il calcolo della profondità e le prestazioni sono peggiori perché è necessario disegnare più geometria.

Ray-Tracing

Il ray tracing è di gran lunga la soluzione più accurata ma anche più costosa per il rendering di volumi trasparenti. Esistono due modi per farlo: 1. Traccia dal fondo dell'oceano verso la superficie e 2. Traccia dalla sorgente luminosa verso l'acqua. Per calcolare la luminosità sono necessari più raggi per ogni punto del pavimento.

Professionisti:

  • Funziona correttamente con ogni geometria.
  • Caustica corretta!

Contro:

  • Lento!

Effetti aggiuntivi

Ci sono alcune altre cose da prendere in considerazione quando si rende l'acqua:

Nebbia

La luce nell'acqua viene nuovamente diffusa mentre viaggia verso l'osservatore, quindi dovresti fonderla verso un colore solido.

Se l'osservatore è immerso , è possibile eseguire il rendering della nebbia in base al risultato finale del buffer di profondità. Il colore della nebbia, ma non la sua densità, dovrebbe cambiare con la distanza dell'osservatore dalla superficie! (Minecraft utilizza solo questa parte dell'effetto.)

Se l'osservatore osserva l'acqua dall'alto , è necessario calcolare la nebbia in base alla differenza di profondità tra la superficie e la geometria sott'acqua. Il colore della nebbia dovrebbe diventare leggermente più scuro con differenze di profondità maggiori, ma dovrebbe cambiare solo nel punto in cui la nebbia è completamente opaca.

Il colore della nebbia dovrebbe anche dipendere dalla direzione della vista per ciascun pixel, quindi è leggermente più scuro quando si guarda in basso in entrambi i casi.

Falsi caustici

Se si utilizza una texture 3D di piastrellatura senza soluzione di continuità anziché una decalcomania per falsi caustici, è possibile evitare l'allungamento su superfici verticali. La forza della luce diffusa vicino alla superficie varia in tre dimensioni, quindi l'uso di una trama 2D di solito produce uno stiramento da qualche parte nella scena. È possibile modellare gli angoli di luce cambiando proiettando le posizioni dei vertici del pavimento in un diverso sistema di coordinate.

Un'altra possibilità è calcolare la densità della luce in base alla posizione della superficie nel sistema di coordinate della luce, anche se molto probabilmente costerebbe alcune prestazioni.

Le sostanze caustiche dovrebbero sbiadire più velocemente della luce diffusa con profondità crescente.

Sfumatura di colore

I colori sono sparsi in modo diverso, quindi il colore della luce dovrebbe cambiare con l'aumentare della profondità. Ciò impedisce anche bordi improvvisi in cui, ad esempio, una spiaggia interseca la superficie dell'acqua.

Angolo di incidenza

A causa della rifrazione, la luce colpisce il fondale oceanico molto più ripida di quanto farebbe normalmente. L' articolo di Wikipedia sulla legge di Snell contiene formule per angoli e vettori.


6

Credo che l'effetto della luce del cielo in Minecraft sia diretto: le cose vengono ombreggiate da ciò che sta sopra, indipendentemente da dove si trovi il sole. Quindi l'illuminazione locale da torce, ecc. Viene applicata con un effetto di discesa: più è lontana dalla sorgente luminosa, meno luce riceve un cubo.

Se fatto in questo modo, ogni strato d'acqua oscurerebbe cumulativamente lo strato sottostante, quindi ognuno diventerà progressivamente più scuro. Il fogliame dell'albero fornisce ombra come questa, tuttavia non è cumulativa. Ottieni la stessa ombra sotto un albero che si tratti di 1 o 100 cubetti di fogliame.

Un indizio del fatto che questo è il metodo utilizzato è che l'acqua non diventa più scura quando è più lontana dallo spettatore - solo mentre scendi. Sì, l'effetto nebbia si attiva a distanza, ma non l'effetto acqua scura.

Quindi la formula di base per calcolare l'illuminazione sarebbe qualcosa di simile in pseudo-codice ...

light_on_cube = 1.0
for each cube above target cube, from lowest to highest {
   if cube being examined is tree foliage
      light_on_cube = 0.5
   else if cube being examined is water
      light_on_cube = light_on_cube - 0.1
   else if cube being examined is solid 
      light_on_cube = 0
}

Questo non è perfetto per il calcolo dell'illuminazione sotto sporgenze o in grotte, poiché con questo metodo sarebbe buio pesto sotto una sporgenza. Ma si potrebbero aggiungere sia fonti di luce locale (torce, fuochi, ecc.) Che trattare i blocchi illuminati dal sole come fonti di luce. Qualcosa del genere potrebbe farlo ...

  1. Calcola la luce del sole direttamente sopra (tramite lo pseudo-codice sopra) per ogni cubo.
  2. Se un cubo ha una sorgente luminosa accanto ad esso, consideralo completamente illuminato (1.0)
  3. Se un cubo non riceve sole direttamente da sopra, dagli un po 'di luce in base a quanto è lontano da un cubo completamente illuminato. Più vicino significa più luce, più lontano significa meno (fino a zero).

L'idea qui è che se un cubo è illuminato dal sole o da una torcia, anche il cubo accanto ad esso verrà illuminato in qualche modo. E più lontano sei da quel cubo illuminato, meno luce ci sarà. È una specie di modo kludge per stimare l'illuminazione diffusa ma penso (?) Che funzionerebbe.


1
Sì, sono abbastanza sicuro che sia il biglietto. Ho fatto qualcosa di simile nel mio gioco.
MichaelHouse

A proposito, ho appena aggiunto il tuo blog al mio elenco di lettori di Google Byte56 - blog degli sviluppatori FTW!
Tim Holt,

Oh, perché grazie. Ancora fuori tema di questa domanda, ma ho appena letto il tuo blog sulla lezione del professor Bailey. Sono stato in quella classe l'anno scorso! Sono abbastanza sicuro che hai fatto anche quella presentazione l'anno scorso. Pensavo che il tuo nome fosse familiare. Piccolo mondo :)
MichaelHouse

3

Forse sto fraintendendo la domanda, ma perché non puoi semplicemente cambiare il colore dei blocchi a seconda della loro profondità?

Se hai la profondità d (in blocchi, a partire da 0), un'equazione ragionevole per la luminosità sarebbe:

L = (1- m ) e - kd + m

Codice: L = (1.0 - m) * exp(-k * d) + m;

k controlla quanto velocemente diventa più scuro (più alto = più veloce). Un valore ragionevole sarebbe 0,5.
m è la luminosità minima desiderata.
L varia da 0 a 1.

Se non sai come cambiare il colore dei blocchi in qualsiasi API grafica che stai utilizzando, ti preghiamo di porre questa domanda separatamente (indicando quale API usi e se stai usando gli shader).


Semplicemente non pensavo di farlo. Solo per curiosità dove hai preso quell'equazione?
Xavier,

1
@Xavier: l'ho appena inventato. Il e^-kdbit è solo un decadimento esponenziale, che è una funzione standard per cose che tendono gradualmente verso lo zero oltre un certo valore (profondità). La moltiplicazione (1-m)e l'aggiunta di msono solo per ridimensionare e compensare il decadimento in modo che finisca al minimo mma inizi comunque a 1. en.wikipedia.org/wiki/Exponential_decay
Peter Alexander

Il fatto è che i blocchi di una tonalità più profonda saranno visibili solo se i blocchi hanno colori alfa; nel qual caso non è necessario cambiare il colore del blocco, l'alfa creerà l'effetto automagicamente.
Jonathan Connell,

@Jonathan: non renderizzi i blocchi d'acqua, rendi i blocchi sul fondo del mare con il colore che si oscura e quindi hai solo un singolo strato alfa sulla superficie dell'acqua.
Peter Alexander,

@Peter Alexander Ok, ho pensato che in questi giochi a blocchi, anche l'acqua fosse fatta di blocchi.
Jonathan Connell,
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.