Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Shaders

Come utilizzare uno Shader per scambiare dinamicamente colori di uno Sprite

by
Difficulty:IntermediateLength:MediumLanguages:

Italian (Italiano) translation by Mirko Pizii (you can also view the original English article)

In questo tutorial, creeremo un semplice colore swapping shader che è possibile ricolorare sprite al volo. Lo shader rende molto più facile per aggiungere varietà ad un gioco, permette al giocatore di personalizzare il loro carattere e può essere utilizzato per aggiungere effetti speciali per gli sprite, come che li rende flash quando il personaggio subisce dei danni.

Anche se stiamo usando l'unità per il demo e il codice sorgente qui, il principio di base funzionerà in molti motori di gioco e linguaggi di programmazione.

Demo

È possibile controllare la demo di unità, o la versione di WebGL (25 MB +), per vedere il risultato finale in azione. Utilizzare i selettori di colore per ricolorare il carattere superiore. (Gli altri personaggi tutti utilizzano lo stesso sprite, ma sono stati ricolorati allo stesso modo). Fare clic su effetto di colpire per rendere i caratteri tutti i flash bianco brevemente.

Comprendere la teoria

Ecco la trama di esempio che andremo ad utilizzare per illustrare lo shader:

Example texture
Ho scaricato questa texture da http://opengameart.org/content/classic-hero e ha modificato leggermente.

Ci sono parecchie colori su questa struttura. Ecco a cosa assomiglia la tavolozza:

A palette

Ora, cerchiamo di pensare a come potremmo scambiarci questi colori all'interno di uno shader.

Ogni colore ha un unico valore RGB associato con esso, così si è tentati di scrivere codice di shader che dice: "Se il colore della trama è uguale a questo valore RGB, sostituirlo con tale valore RGB". Tuttavia, questo non scala bene per molti colori ed è abbastanza un'operazione costosa. Ci piacerebbe sicuramente evitare qualsiasi istruzioni condizionali interamente, in realtà.

Invece, utilizzeremo un supplementare di texture, che conterrà i colori di sostituzione. Let's chiamare questa texture una texture di swap.

La grande domanda è, come colleghiamo il colore dalla trama sprite al colore dalla texture di swap? La risposta è, useremo il componente rosso (R) dal colore RGB per indicizzare la texture di swap. Ciò significa che la trama di scambio dovrà essere 256 pixel di larghezza, perché questo è il numero di valori diverso può prendere la componente rossa.

Ripassiamo tutto questo in un esempio. Qui ci sono i valori di colore rosso di colori della tavolozza sprite:

R color values for palette

Diciamo che vogliamo sostituire il colore di contorno/occhio (nero) sullo sprite con il colore blu. Il colore del contorno è l'ultimo sulla tavolozza — quello con un valore di colore rosso di 25. Se vogliamo cambiare questo colore, allora nella texture swap abbiamo bisogno di impostare il pixel all'indice 25 per il colore che vogliamo il contorno di essere: blu.

Swap texture with blue highlighted
La struttura di scambio, con il colore all'indice 25 impostato su blu.

Ora, quando lo shader rileva un colore con un valore di 25 rosso, esso sostituirà con il colore blu dalla trama swap:

The swap texture in action

Si noti che questo potrebbe non funzionare come previsto se due o più colori sulla trama di sprite condividono lo stesso valore di rosso! Quando si utilizza questo metodo, è importante tenere i valori di rossi dei colori la trama di sprite differenti.

Si noti inoltre che, come si può vedere nella demo, mettendo un pixel trasparente a qualsiasi indice della texture di swap si tradurrà in nessun colore scambiando per i colori corrispondenti a tale indice.

Esecuzione dello Shader

Implementeremo questa idea modificando uno shader di sprite esistenti. Poiché il progetto demo viene effettuato in unità, si utilizzerà lo shader di sprite di unità predefinito.

Tutto ciò non lo shader predefinito (che è rilevante per questo tutorial) è campione il colore dall'Atlante texture principale e moltiplicare quel colore di un colore di vertice per modificare la tinta. Il colore risultante viene quindi moltiplicato per l'alfa, per rendere più scuro lo sprite alle opacità inferiore.

La prima cosa che dobbiamo fare è aggiungere una texture aggiuntiva allo shader:

Come potete vedere, abbiamo due texture qui adesso. Il primo, _MainTex, è la trama di sprite; il secondo, _SwapTex, è la trama di swap.

Abbiamo anche bisogno di definire un sampler per la seconda texture, quindi in realtà possiamo accedervi. Useremo un campionatore di trame 2D, poiché l'unità non supporta campionatori 1D:

Ora finalmente possiamo modificare lo shader di frammento:

Ecco il codice pertinente per lo shader di frammento predefinito. Come potete vedere, c è il colore campionato dalla trama principale; viene moltiplicato per il colore del vertice per dargli una tinta. Inoltre, lo shader si scurisce gli sprite con opacità inferiore.

Dopo aver assaggiato il colore principale, diciamo campionare il colore di swap anche — ma prima di farlo, Let's rimuovere la parte che moltiplica per il colore della tinta, in modo che noi stiamo campionamento utilizzando valore reale rosso della trama, non è uno colorato.

Come potete vedere, l'indice di colore campionato è uguale al valore rosso del colore principale.

Ora proviamo a calcolare il nostro colore finale:

Per fare questo, abbiamo bisogno di interpolare tra il colore principale e il colore scambiato utilizzando l'alfa del colore scambiato come il passo. In questo modo, se il colore scambiato è trasparente, il colore finale sarà uguale al colore principale; ma se il colore scambiato è completamente opaco, quindi il colore finale sarà uguale al colore scambiato.

Non dimentichiamo che il colore finale deve essere moltiplicato per la tinta:

Ora dobbiamo considerare che cosa dovrebbe accadere se vogliamo scambiare un colore sulla principale trama che non è completamente opaco. Ad esempio, se abbiamo uno sprite fantasma blu, semi-trasparente e vuole scambiare il suo colore di viola, non vogliamo che il fantasma con i colori invertiti per essere opaco, vogliamo preservare la trasparenza originale. Facciamo cosi:

La trasparenza del colore finale deve essere uguale alla trasparenza sul colore della trama principale.

Infine, poiché lo shader originale era moltiplicando il valore del colore RGB per alfa del colore, dovremmo farlo troppo, al fine di mantenere lo shader lo stesso:

Lo shader è stato completo; possiamo creare una texture di colore swap, riempirlo con i pixel di colore diverso e vedere se lo sprite cambia colori correttamente.

Naturalmente, questo metodo non sarebbe molto utile se abbiamo dovuto creare texture di swap a mano tutto il tempo! Noi vogliamo generare e modificarli in modo procedurale...

Creazione di un Demo di esempio

Sappiamo che abbiamo bisogno di una texture di swap per essere in grado di fare uso della nostra shader. Inoltre, se vogliamo lasciare più caratteri utilizzare tavolozze diverse per lo stesso sprite allo stesso tempo, ognuno di questi personaggi bisogno la propria trama di swap.

Sarà meglio, quindi, se creiamo semplicemente queste texture di swap in modo dinamico, come creiamo gli oggetti.

Per prima cosa, definiamo una texture di swap e una matrice in cui ci potrai tenere traccia di tutti i colori invertiti:

Quindi, creiamo una funzione in cui inizializziamo la texture. Il sistema utilizza RGBA32 formato e impostare la modalità di filtro per punto:

Ora facciamo in modo che i pixel della texture siano trasparenti, disattivando tutti i pixel e applicare le modifiche:

Abbiamo anche bisogno di impostare la trama del materiale swap a quello appena creato:

Infine, salvare il riferimento alla consistenza e creare la matrice per i colori:

La funzione completa è la seguente:

Si noti che non è necessario per ogni oggetto per utilizzare una trama separata 256x1px; Potremmo fare una texture più grande che copre tutti gli oggetti. Se abbiamo bisogno di 32 caratteri, potremmo fare una texture di dimensioni 256x32px e assicurarsi che ogni personaggio utilizza solo una riga specifica in quella trama. Tuttavia, ogni volta che avevamo bisogno di fare un cambiamento a questa trama più grande, che avremmo dovuto passare più dati alla GPU, che probabilmente renderebbe questo meno efficiente.

Inoltre, non è necessario utilizzare una texture di swap separata per ogni sprite. Ad esempio, se il personaggio ha un'arma equipaggiata, e quell'arma è uno sprite separato, allora si può facilmente condividere la texture di swap con il carattere (purché trama sprite dell'arma non fa uso di colori che sono rossi valori identici a quelli del personaggio Sprite).

È molto utile sapere quali sono i valori rossi delle parti particolare sprite, pertanto creiamo un enum che conterrà i dati:

Questi sono tutti i colori utilizzati dal carattere di esempio.

Ora abbiamo tutte le cose che abbiamo bisogno di creare una funzione per cambiare effettivamente il colore:

Come potete vedere, non c'è niente qui; Abbiamo solo impostare il colore colore matrice del nostro oggetto e anche impostare il numero di pixel della texture a un indice appropriato.

Nota che non vogliamo davvero applicare le modifiche alla struttura ogni volta che chiamiamo effettivamente questa funzione; sarebbe piuttosto applicarle una volta che ci scambiamo tutti i pixel che vogliamo.

Diamo un'occhiata a un esempio di utilizzo della funzione:

Come potete vedere, è abbastanza facile da capire che cosa questi chiamate di funzione stanno facendo solo da loro lettura: in questo caso, stanno cambiando entrambi i colori della pelle, sia i colori della camicia e il colore di pantaloni.

Aggiunta di un effetto di colpo alla Demo

Vediamo quindi come possiamo usare lo shader per creare un effetto di colpo per il nostro sprite. Questo effetto si scambia colori dello sprite per bianco, mantenere in questo modo per un breve periodo di tempo e poi tornare al colore originale. L'effetto complessivo sarà che lo sprite lampeggia in bianco.

Prima di tutto creiamo una funzione che consente di scambiare tutti i colori, ma in realtà non sovrascrive i colori dalla matrice dell'oggetto. Avremo bisogno di questi colori quando vogliamo spegnere l'effetto di colpo, dopo tutto.

Abbiamo potuto scorrere solo le enumerazioni, ma scorrendo la trama intera garantirà che il colore viene scambiato anche se un colore particolare non è definito nella SwapIndex.

Ora che i colori sono invertiti, abbiamo bisogno di attendere qualche tempo e tornare indietro ai colori precedenti.

In primo luogo, creiamo una funzione che reimposterà i colori:

Ora definiamo il timer e una costante:

Creiamo una funzione che avrà inizio l'effetto di colpo:

La funzione di aggiornamento, Let's controllare quanto tempo è rimasto il timer, diminuire ogni tick e chiamare per un reset quando il tempo è scaduto:

Questo è tutto — ora, quando StartHitEffect viene chiamato, lo sprite flash bianco per un momento e poi tornare al suoi precedente colori.

Riepilogo

Questo segna la fine del tutorial! Spero che trovi il metodo accettabile e lo shader utile. È davvero semplice, ma funziona bene per gli sprite di arte del pixel che non utilizzano molti colori.

Il metodo avrebbe bisogno di essere cambiato un po' se abbiamo voluto scambiare interi gruppi di colori in una sola volta, che sicuramente richiederebbe uno shader più complicato e costoso. Nel mio gioco, però, sto usando molto pochi colori, così questa tecnica si adatta perfettamente.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.