Come posso implementare un'illuminazione uniforme basata su piastrelle?


8

Ho lavorato su un gioco di tessere 2D e ho implementato l'illuminazione a spigoli vivi:

inserisci qui la descrizione dell'immagine

Voglio che sia appianato un po '. Non ho bisogno di ombre o altro, solo di una semplice illuminazione. Vorrei che fosse più simile a questo:

inserisci qui la descrizione dell'immagine

Il mio sistema attuale utilizza livelli di luce per ogni tessera del mondo e vengono ricalcolati quando una tessera viene posizionata o rimossa. Sto usando batch.setColor(...)per ombreggiare le piastrelle. Qual è un buon modo per ottenere questa illuminazione uniforme?

Non voglio usare il metodo di sovrapposizione della mappa di luce, l'ho già provato e non ero soddisfatto del risultato. Voglio essere in grado di impostare quanta luce è in grado di passare attraverso un blocco. Ad esempio, un blocco di sporco dovrebbe assorbire parte della luce, ma un blocco di vetro non dovrebbe bloccare alcuna luce. Ciò non era realmente possibile con il metodo di sovrapposizione della mappa di luce. AGGIORNAMENTO: ho capito male che cosa sia effettivamente questo metodo. Ora capisco. Stavo pensando nel modo sbagliato. Scusate!


Ad essere onesti, sembra più elegante con un'illuminazione dai bordi rigidi.
S. Tarık Çetin,

Non mi piace così tanto, è anche un po 'difficile differenziare le tessere di sfondo e le tessere di primo piano con questo stile.
ProRed

Risposte:


15

Un modo semplice per ottenere un'illuminazione uniforme in un gioco basato su tessere è quello di disegnare una "mappa luminosa" su un obiettivo di rendering, quindi disegnare questo obiettivo di rendering sopra la scena mentre lo si fonde alfa.

Il target di rendering della mappa di luce dovrebbe avere le dimensioni della mappa di piastrelle, ma in pixel. Ogni pixel rappresenterebbe il colore chiaro della sua tessera corrispondente. Questa trama di rendering sarebbe simile a questa (trama in alto a sinistra in bianco e nero):

inserisci qui la descrizione dell'immagine

Una volta che hai questa texture mappa leggera, puoi quindi disegnarla come una sovrapposizione sul tuo mondo di gioco (allungata). Dovrai bloccarlo correttamente, in modo che si estenda perfettamente sopra le tue tessere nel mondo di gioco.

Quindi si tratta di mescolare alfa questa trama con il tuo mondo di gioco in libGDX. Per unire LibGDX (personalmente non so come), potresti dover guardare la Gdx.gl.glBlendFuncfunzione.


2
È possibile controllare l'illuminazione nel modo desiderato con questo sistema. Non sono sicuro di cosa ti riferisci quando dici che non puoi bloccare la luce. Inoltre, non sei del tutto sicuro di come prevedi di appianare il tuo sistema attuale, dato che stai letteralmente semplicemente colorando le tue piastrelle.
Jgallant,

4
A proposito, questo sistema è il modo in cui Starbound lo fa.
Qqwy,

2
Questo è un ottimo approccio e consente flessibilità dove è necessario. Lo uso nel mio gioco basato su tessere in cui non ho accesso agli shader e funziona alla grande!
Tyyppi_77,

1
AGGIORNAMENTO : Questa sembra la strada da percorrere, ho capito male questo metodo e ora capisco perfettamente! Cercherò di implementare questo metodo ora e lo segnerò come la migliore risposta e ti darò la generosità!
ProRed

2
Se hai ulteriori domande su come farlo, sentiti libero di chiedere. Ho implementato questo e @ Tyyppi_77 lo ha fatto anche di recente. L'ho fatto in XNA / Monogame e Unity. Tyyppi lo ha fatto in SDL.
Jgallant,

4

un modo agnostico del motore per farlo è utilizzare la mappatura della luce media. Innanzitutto, è necessario generare una mappa in bianco e nero come una matrice 2D di valori booleani delle dimensioni del mondo in cui i blocchi sono Veri e vuoti è Falso.

In questo modo (1 è nero, 0 è bianco): carta geografica

Quindi è necessario creare un nuovo array 2D che abbia le stesse dimensioni del primo array ma che sia un array di float. Quindi si passa da un blocco nero (Vero) a un blocco nero nell'array e si calcola la media del valore campionato vicino (spiegato di seguito)

Questa immagine aiuterà: media

Questa immagine rappresenta il campionamento (dove + significa falso e | significa vero). ciò che facciamo è trattare i valori Veri come 1 e i valori Falsi come 0. Quindi si calcolano la media dei 9 numeri e li si inserisce nella parte corretta dell'array. NOTA: assicurarsi che durante il campionamento dei bordi si utilizzino i valori esterni come sensibili al contesto. Ad esempio: sotterranea la mappa al di fuori del mondo potrebbe essere 1 e il cielo dovrebbe essere 0.

Dovrebbe apparire così (preso da altri post):fine

Quindi tutto ciò che devi fare è colorare ciascun blocco dell'array con

rgba(tint,tint,tint,1)

(tinta = il valore di blocco medio corrente nel secondo array e alpha non ha importanza). Nota: questo presuppone che la pseudo-funzione rgba prenda float da 0-1 invece di 0-255, se lo fa, basta fare questo:

rgba(tint*255,tint*255,tint*255,255)

Spero che questo abbia un po 'di senso :) Se vuoi il codice, chiedi!


Grazie per la risposta, ma il fatto è che ho già un'illuminazione dura nel mio gioco ( qui ). Ho chiesto come avrei potuto cambiare questo aspetto per
renderlo

1

Dato che stai parlando di cose che bloccano la luce, presumo che tu abbia qualche modello su come la luce dovrebbe diffondersi. Ad esempio, tutto senza blocchi sopra è completamente illuminato, la luce si diffonde a tutte le celle vicine ma perde una certa luminosità.

Dovresti essere in grado di implementare queste regole abbastanza facilmente dal lato software, almeno la parte di smoothing è solo una questione di lancio di shader sulla mappa della luce che hai generato.

I metodi che altri hanno suggerito con la sovrapposizione di una mappa luminosa sono qualcosa che dovresti comunque fare. Ma puoi cambiare il modo in cui generi questa mappa luminosa. Inizialmente puoi riempirlo con solo le informazioni sul blocco, ma ad esempio puoi ridimensionarlo e renderlo più uniforme in uno shader. Un ulteriore vantaggio dell'approccio con la mappa della luce è che puoi semplicemente disegnare luci dinamiche nella tua mappa della luce anche per evidenziare esplosioni o cosa hai e si fonderà naturalmente con il resto del tuo mondo.

Aggiungi elementi di fusione addizionali alla tua mappa luminosa e poi mescola la tua mappa luminosa con il mondo di gioco.

Ho fatto questo qualche tempo fa che utilizza gli stessi principi. Questo sistema non supporta la caduta di luce in modo diverso per diversi tipi di terreno, ma almeno dovrebbe illustrare l'utilità di sovrapporre una mappa di luce.


Vedo, quindi renderei i livelli di luce in forma di rettangoli che hanno esattamente le dimensioni della piastrella corrispondente su un secondo target di rendering? E come potrei fare per lisciarlo?
ProRed

Puoi lasciare che la GPU la gestisca effettuando il downsampling, poiché durante il rendering ti interpolerà linearmente. Se ciò non è abbastanza buono, puoi eseguire una sorta di sfocatura su di esso in uno shader. Puoi anche considerare di eseguire il rendering in granularità più fine rispetto alla risoluzione delle piastrelle se vuoi disegnarla in modo diverso a seconda delle piastrelle adiacenti. Fondamentalmente la parte difficile è trovare le regole specifiche che desideri per quale area dovrebbe essere illuminata quanto. Se scrivi quelle regole di solito troverai un modo abbastanza semplice per farlo.
Nils Ole Timm,

1

È abbastanza facile per una torcia: usando un pixel shader personalizzato si calcola la distanza tra ciascun frammento e la torcia; puoi quindi calcolare dove si trova la prima tessera densa che blocca la luce proveniente dalla torcia. Quindi calcolare la distanza in cui la luce non è bloccata, moltiplicarla per qualcosa <1 in modo che la torcia non illumini il sole, sottrarla dalla distanza totale e ripetere per il resto della distanza (dove la luce è stata bloccata da almeno una tessera) con un valore di moltiplicazione molto più piccolo ... So come fare questa matematica e non è troppo complicato da implementare in OpenGL.

EDIT: per una semplice sorgente luminosa con un punto centrale specifico, il mio metodo è estremamente semplice. Tuttavia il mio non funziona con la luce solare, ma mentre la mappa alfa funziona davvero bene per la luce del sole, NON sarebbe una buona idea per una torcia, dato che è potenzialmente un oggetto in movimento e creare una nuova mappa ogni fotogramma non è piacevole esperienza di vita. La migliore soluzione secondo me è un mix: il calcolo della distanza per luci specifiche che sono in realtà oggetti nel gioco, uno shader separato che puoi semplicemente lanciare sulla mappa alfa generata proceduralmente usando la tecnica menzionata sopra: una trama di tutte le piastrelle sfocano nella tua dura ombreggiatura, come un sacco di quadrati, e si divertono con le tecniche per appianare.


0

Il tuo rendering usa i colori dei vertici (o puoi cambiarlo)?

Supponendo che ogni blocco sia un quadrato a 4 vertici, che ti darebbe un paio di opzioni, ad esempio:

Se il tuo attuale algoritmo di illuminazione ti dà un valore di luce per blocco, puoi cambiarlo per darti un valore per vertice. In alternativa, ad ogni vertice è possibile calcolare la media del colore chiaro del blocco corrente più i suoi tre vicini. Entrambe le soluzioni sarebbero economiche.

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.