Texture

Segui queste best practice per ottimizzare l'aspetto e le prestazioni delle texture nel tuo gioco Android.

Le texture sono un elemento fondamentale della tua grafica 3D. I giochi 3D che funzionano bene sul maggior numero di dispositivi iniziano con la grafica 3D, progettata per sfruttare al meglio i processori grafici. Questa guida evidenzia le ottimizzazioni e le best practice per le texture sui dispositivi mobili al fine di migliorare le prestazioni del tuo gioco e ridurre al minimo il consumo energetico mantenendo un'alta qualità visiva.

Alcune parti di questo articolo si basano sull'opera realizzata e protetta da copyright di Arm Limited.

Crea atlanti di texture

Un atlante di texture è una texture progettata per contenere i dati immagine di più oggetti grafici, come mesh 3D o sprite 2D. Invece di ogni oggetto con una propria texture, viene utilizzata una texture atlante per combinare le immagini di ciascun oggetto.

Maglie che condividono un atlante di texture
Figura 1. L'evidenziazione gialla nella scena visualizzata (a sinistra) delinea le maglie che condividono l'atlante delle texture (a destra).

Ridurre al minimo il numero di chiamate di disegno del frame di un gioco è un elemento importante per ottenere prestazioni di rendering ottimali. L'uso della stessa texture per oggetti diversi è uno dei fattori per combinarli in un'unica chiamata di disegno. La riduzione delle chiamate di disegno è particolarmente importante per i giochi legati alla CPU, poiché ogni chiamata di disegno comporta un overhead per la CPU mentre viene elaborata dal driver di grafica. Gli atlanti di texture riducono anche il numero di file di asset delle texture nei dati di runtime del gioco. È possibile consolidare centinaia o addirittura migliaia di texture in un numero molto più ridotto di file atlante di texture.

Quando crei mesh 3D, è consigliabile pianificare il layout dell'atlante delle texture. Se l'atlante viene creato prima di creare l'asset mesh, quest'ultimo deve essere senza wrapper per UV seguendo l'atlante della texture. Se l'atlante viene creato dopo la creazione, utilizzando strumenti di unione o creazione di atlanti nei software di disegno, l'isola UV dovrà essere riorganizzata in base alla texture.

Batch di chiamate di disegno specifiche del motore

Il motore di gioco Unity è dotato di una funzionalità di raggruppamento delle chiamate di disegno, in grado di combinare automaticamente gli oggetti. Per essere idonei al batch automatico, gli oggetti devono condividere un materiale comune, incluse le texture, ed essere contrassegnati come statici.

Unreal Engine 4 richiede la configurazione manuale per la creazione in batch. Puoi unire gli oggetti nel software 3D prima di importarli in Unreal. Unreal include anche lo strumento UE4 Actor Merging, che può combinare mesh e creare file atlante di texture.

Genera Mipmap

Le mappe Mipmap sono versioni a risoluzione inferiore di una trama. Una raccolta di mipmap per una data trama è chiamata catena mipmap. Ogni livello di mipmap successivo in una catena ha una risoluzione inferiore rispetto al livello precedente. Le Mipmap vengono utilizzate per implementare il livello di dettaglio (LOD) della trama durante il rendering. Quando una texture mipmappata è legata a uno stage di texture, l'hardware grafico utilizza lo spazio di texture occupato da un frammento per scegliere un livello dalla catena delle mappe mipmap. Durante il rendering di una scena 3D, un oggetto più lontano dalla fotocamera utilizza una mipmap con risoluzione inferiore rispetto allo stesso oggetto più vicino alla fotocamera.

Una texture mipmappata utilizza più memoria rispetto a una texture non mipmappata. I livelli di mipmap aggiuntivi aumentano del 33% l'impronta di memoria di una texture. Se una texture viene disegnata a una distanza fissa dalla fotocamera, la generazione di mipmap è un uso non necessario della memoria.

Una catena mipmap con una risoluzione della texture di base di 512 x 512 pixel
Figura 2. In una catena di mipmap, la risoluzione di base della texture è 512 x 512 pixel.

L'uso corretto delle mipmap migliora le prestazioni della GPU. La disponibilità di livelli di mipmap a risoluzione inferiore riduce l'utilizzo della larghezza di banda della memoria e migliora la residenza della cache delle texture.

Il Mipmapping può anche migliorare la qualità visiva riducendo l'aliasing delle texture. L'aliasing della trama può essere osservato come un effetto tremolante sulle aree più distanti dalla fotocamera.

Esempio di aliasing delle texture
Figura 3. Un esempio di aliasing delle texture. Un'immagine viene visualizzata senza mipmap (a sinistra), l'altra con mipmap (a destra). All'interno del rettangolo rosso nell'immagine a sinistra è possibile osservare l'aliasing della texture.

Dettagli mipmap specifici del motore

Unreal Engine 4 richiede dimensioni delle texture con potenze di due (ad es. 512 x 1024, 128 x 128) per utilizzare la mipmapping. Le catene MIME non verranno generate se una o entrambe le dimensioni della texture non sono una potenza di due.

Il motore Unity scala automaticamente le texture con dimensioni che non possono essere uguali a due per creare mipmap. Assicurati che i file delle texture di origine abbiano due dimensioni per evitare questo ridimensionamento.

Seleziona le modalità di filtro delle texture appropriate

Il filtro delle texture è una funzionalità di rendering hardware che influisce sull'aspetto visivo di un triangolo visualizzato. L'uso appropriato del filtro della texture può migliorare la qualità visiva di una scena. Esistono più modalità di filtro delle texture, ognuna con un diverso equilibrio tra miglioramento del rendering e costo. Il costo include sia il tempo di calcolo sia la larghezza di banda della memoria. Le tre modalità di filtro delle texture comunemente disponibili sono: più vicina (o punto), bilineare e trilineare. Anisotropico è un ulteriore metodo di filtro delle texture che può essere combinato con un filtro bilineare o trilineare.

Il più vicino

La più vicina è la modalità di filtro delle texture più semplice e meno costosa. Il valore più vicino campiona un singolo testo utilizzando le coordinate specificate nella texture di origine. I triangoli visualizzati con l'immagine più vicina avranno un aspetto squadrato o pixelato, soprattutto se visualizzati vicino alla fotocamera.

Bilineare

Il filtro bilineare campiona i quattro texel che circondano le coordinate specificate nella texture di origine. Viene calcolata la media di questi quattro tex per determinare il colore della trama del frammento. Il filtro bilineare produce un gradiente più uniforme tra i pixel, evitando l'aspetto a blocchi del filtro più vicino. I triangoli visualizzati vicino alla fotocamera appariranno sfocati anziché pixelati. La rete bilineare costa di più rispetto al più vicino a causa dei campioni di testo aggiuntivi e del calcolo della media.

Confronto tra filtri più vicini e bilineari
Figura 4. Un confronto tra i filtri di texture più vicini (a sinistra) e bilineari (a destra).

Trilineare

Quando esegui il rendering di un mesh in cui la distanza dei vertici dalla fotocamera varia, durante il rendering possono essere selezionati più livelli di mipmap. I cambiamenti tra due livelli di mipmap possono portare a un notevole taglio nel punto di transizione. Il filtro trilineare attenua queste transizioni eseguendo filtri bilineari su due diversi livelli di mipmap e interpolando i risultati. L'uso di più livelli mip e di interpolazione rende la trilinea più costosa di calcolo rispetto a quella bilineare.

Confronto tra filtri bilineare e trilineare
Figura 5. Un confronto tra filtri di texture bilineare (sinistra) e trilineare (destra). La regione ingrandita mette in contrasto la differenza di rendering durante le transizioni mipmap.

Anisotropico

Il filtro anisotropico aumenta la qualità visiva dei mesh con texture che vengono visualizzati a un'angolazione estrema rispetto alla fotocamera. Un piano di terra è un esempio comune di questo tipo di mesh. Il filtro anisotropico richiede texture mipmappate per funzionare. È possibile configurare il rapporto o il livello di filtro anisotropico applicato durante il rendering. Il costo del filtro anisotropico aumenta con l'aumentare del livello.

Un confronto tra filtri anisotropici 1x e 2x
Figura 6. Un confronto del filtro bilineare/1x anisotropico (a sinistra) e del filtro bilineare/2x anisotropico (a destra)

Strategia di selezione della modalità

Il filtro bilineare rappresenta in genere il miglior equilibrio tra rendimento e qualità visiva. Il filtro trilineare richiede una larghezza di banda di memoria notevolmente maggiore e deve essere utilizzato in modo selettivo. In molti casi, il filtro bilineare combinato con il filtro anisotropico 2x avrà un aspetto e prestazioni migliori rispetto al filtro trilineare con un filtro anisotropico 1x. Aumentare i livelli anisotropici oltre il doppio è estremamente costoso e dovrebbe essere fatto in modo molto selettivo per le risorse di gioco critiche.

Il filtro delle texture può rappresentare fino alla metà del consumo totale di energia della GPU, scegliendo filtri di texture più semplici, ove possibile, è un modo eccellente per ridurre il consumo di energia del gioco.

Ottimizza le dimensioni delle texture

Assicurati che le dimensioni della texture siano le più ridotte possibili, pur garantendo la qualità dell'immagine desiderata. Rivedi gli asset delle texture per verificare se sono presenti texture troppo grandi. Questo principio si applica alle texture sia discrete sia atlanti. Se il tuo gioco supporta molti dispositivi che comprendono un'ampia gamma di funzionalità di risoluzione e prestazioni, valuta la possibilità di creare versioni a bassa e alta risoluzione degli asset texture per la classe di dispositivo appropriata.

Quando esegui il rendering di una rete mesh che utilizza più texture nel materiale, valuta la possibilità di ridurre selettivamente la risoluzione di alcune texture. Ad esempio, quando utilizzi una texture diffusa di 1024 x 1024, è possibile ridurre la rugosità o la texture di mappa metallica a 512 x 512 con un impatto minimo sulla qualità dell'immagine. Verifica l'impatto di tutti questi esperimenti di ridimensionamento per assicurarti che non compromettano il livello qualitativo desiderato.

Utilizza lo spazio colore appropriato

Molti pacchetti software utilizzati per la creazione di texture operano ed esportano utilizzando lo spazio colore sRGB. Le texture diffuse, che vengono elaborate come colori, possono utilizzare lo spazio colore sRGB. Le texture che non vengono elaborate come colori, ad esempio metallica, rugosità o mappe normali, non devono essere esportate nello spazio colore sRGB.

Le impostazioni delle texture del motore di gioco includono un parametro che determina se una texture utilizza lo spazio colore sRGB.

Impostazioni delle texture sRGB in Unity e Unreal Engine 4
Figura 7. Impostazioni delle texture sRGB in Unity (sinistra) e Unreal Engine 4 (destra).

Poiché i dati dei pixel di queste texture non vengono utilizzati come dati sui colori, l'uso dello spazio colore sRGB produrrà immagini errate.

Rendering di un uomo con metallo ruvido in uno spazio colore lineare e sRGB
Figura 8. Una mappa metallica con rugosità lineare (non sRGB) (a sinistra) e mappa metallica con rugosità sRGB (a destra). I riflessi sulla destra sembrano errati.

Utilizza la compressione delle texture

La compressione delle texture è un algoritmo di compressione delle immagini applicato ai dati di pixel non compressi che genera una texture che può essere rapidamente decompressa dall'hardware della grafica durante il rendering. L'uso efficace della compressione delle texture può ridurre l'utilizzo della memoria e aumentare le prestazioni con un impatto minimo sulla qualità visiva. Tre algoritmi di compressione delle texture sono più comuni su Android: ETC1, ETC2 e ASTC. Per i giochi moderni, ASTC è in genere l'opzione principale migliore; ETC2 è un'opzione di riserva se il tuo gioco ha come target dispositivi che non supportano ASTC.

ETC1

ETC1 è supportato da tutti i dispositivi Android. ETC1 supporta solo una modalità a quattro bit per pixel dei dati di colore RGB. ETC1 non supporta i canali alfa. Molti motori di gioco che supportano ETC1 consentono la designazione di una seconda texture ETC1 da utilizzare per rappresentare i dati del canale alfa.

ETC2

ETC2 è supportato da oltre il 90% dei dispositivi Android attivi. I dispositivi molto vecchi che non supportano l'API OpenGL ES 3.0 non possono utilizzare ETC2. Rispetto a ETC1, ETC2 aggiunge:

  • Supporto del canale alfa, "punchthrough" a otto bit e a bit singolo
  • Versioni sRGB di texture RGB e RGBA
  • Un canale e due, R11 e RG11, texture

ASTC

ASTC è supportato da oltre il 75% dei dispositivi Android attivi. ASTC dispone di dimensioni dei blocchi di compressione configurabili, che offrono un controllo granulare per bilanciare il rapporto di compressione e la qualità dell'immagine di una determinata texture. ASTC è spesso in grado di raggiungere una qualità superiore con le stesse dimensioni della memoria di ETC2 o quantità simili con una memoria di dimensioni inferiori rispetto a ETC2.

Un confronto visivo tra i formati di compressione delle texture che utilizzano la stessa immagine di origine
Figura 9. Un confronto tra immagini: non compresse (a sinistra, di 17 MB), compresse con ETC1 (al centro, di 3 MB), compresse con ASTC (a destra, dimensioni di 2,5 MB).

Velocità di compressione delle texture

La compressione delle texture può richiedere molto tempo se il tuo gioco ha molte texture. Sia ETC che ASTC hanno impostazioni selezionabili per la qualità della compressione. La compressione delle impostazioni di qualità superiore richiede più tempo. Durante lo sviluppo, potresti voler ridurre il livello qualitativo per ridurre il tempo di compressione e aumentare il livello qualitativo prima di creare build importanti.

Compressione delle texture nei motori di gioco

Se utilizzi un motore di gioco, potresti dover scegliere il formato di compressione delle texture (ETC o ASTC) a livello di progetto. Per supportare più formati di compressione e ottenere la massima compatibilità, potrebbe essere necessario eseguire altre operazioni. La funzionalità di targeting per formato di compressione delle texture di Google Play Asset Delivery può aiutarti a includere più formati nel tuo gioco e a fornire solo il formato più ottimale a un singolo dispositivo al momento dell'installazione.

Scarta i raggi UV

Mantieni l'isola UV il più dritta possibile. Ciò favorisce la texture nei seguenti modi:

  • L'imballaggio delle isole UV è più facile e riduce lo spazio sprecato.
  • I raggi UV dritti riducono l'effetto scala sulle texture.
  • Un buon rivestimento UV assicura una risoluzione ottimale dalla texture.
  • Texture migliore, anche se i raggi UV sono leggermente distorti e non si raddrizzano.
Un'isola UV non ottimizzata rispetto a un'isola UV ottimizzata
Figura 10. Un'isola UV non ottimizzata (a sinistra) e un'isola UV raddrizzata/non avvolta (a destra).

Le cuciture visibili delle texture su un modello non sono corrette. Cerca di posizionare eventuali cuciture UV in punti in cui sono meno visibili. Per creare mappe normali migliori, dividi l'isola UV dove i bordi sono nitidi e lascia un po' di spazio intorno all'isola.

Evita dettagli impercettibili

Quando crei opere d'arte, non aggiungere dettagli che non saranno visibili, in particolare nei giochi progettati per dispositivi con schermi più piccoli. La creazione di una trama 4096 x 4096 riccamente dettagliata viene sprecata per un modello di piccola sedia appena visibile all'angolo di una stanza. In alcuni casi potrebbe essere necessario esagerare i bordi (aggiungendo evidenziazione) e l'ombreggiatura per migliorare la percezione della forma.

Una piccola texture viene utilizzata su un modello visualizzato a distanza
Figura 11. Una piccola trama 256 x 256 priva di dettagli eccessivi viene utilizzata su un modello militare renderizzato a distanza.

Dettagli cuocere

I dispositivi mobili hanno schermi più piccoli e hardware grafico meno potente rispetto ai computer o alle console per videogiochi. Invece di calcolare effetti come l'occlusione dell'ambiente o l'evidenziazione speculare al momento dell'attivazione, potresti "infornarli" nella texture diffusa, quando possibile. Ciò migliora le prestazioni e garantisce la visibilità dei tuoi dettagli.

Le alte luci soffuse e la copertura ambientale creano una trama diffusa
Figura 12. Le luci e l'occlusione ambientale sono integrati nella texture diffusa (a sinistra) e visualizzati nel gioco (a destra).

Usa colorazione colore

Se sei in grado di creare mesh personalizzati e hai mesh con una combinazione di colori simile o uniforme, valuta la possibilità di utilizzare la colorazione dei colori sui livelli applicabili. Con la colorazione dei colori, viene utilizzata una texture in scala di grigi, che richiede meno memoria della trama rispetto a una texture RGB. I dati di colore per vertice vengono applicati dall'ombreggiatura per colorare la mesh. Un metodo di colorazione alternativo consiste nell'utilizzare una maschera RGB e applicare la texture in base all'intervallo di colori della maschera.

Una texture in scala di grigi colorata al momento dell'attivazione
Figura 13. Una texture in scala di grigi (a sinistra) colorata al momento dell'attivazione per il modello dei pilastri (a destra).

Crea canali di texture

Quando esegui il rendering di materiali con più texture, cerca opportunità di combinare texture che utilizzano un solo canale di colore in un'unica texture che utilizzi tutti e tre i canali di colore. In questo modo viene ridotto l'utilizzo della memoria e il numero di operazioni di campionamento delle texture eseguite dallo Shader frammenti.

Tre texture monocanale combinate in un'unica texture multicanale
Figura 14. Tre texture monocanale (a sinistra) vengono combinate in un'unica texture multicanale (a destra). I dati relativi all'occlusione ambientale vengono assegnati al rosso, al verde la mappa di rugosità/liscio e al blu la mappa metallica.

Durante la presentazione, assegna i dati con il maggior numero di dettagli al canale verde. Poiché l'occhio umano è più sensibile al verde, l'hardware della grafica di solito assegna più bit al canale verde. Ad esempio, una mappa di rugosità/liscio ha in genere più dettagli di una mappa metallica ed è una scelta migliore da assegnare al canale verde.

Per i materiali che utilizzano un canale alfa, se utilizzi solo due canali nella texture pacchettizzata, valuta la possibilità di inserire i dati del canale alfa nella trama pacchettizzata anziché nella texture diffusa. A seconda del formato della texture diffusa, questo può aiutarti a ridurne le dimensioni o ad aumentare la qualità visiva omettendo i dati del canale alfa.

Un canale alfa integrato in un'altra texture
Figura 15. Una mappa dell'opacità del canale alfa è pacchettizzata in una texture insieme a una mappa di rugosità/liscio e a una mappa metallica.

Assicurati che le texture pacchetti siano impostate su uno spazio colore RGB lineare e non su sRGB.

Crea mappe normali

La mappatura normale è una tecnica che fornisce a un modello 3D l'aspetto dei dettagli senza utilizzare elementi geometrici aggiuntivi. Funzionalità come pieghe o bulloni, che potrebbero richiedere molti triangoli da modellare, possono essere simulate utilizzando una mappa normale. Una mappatura normale può essere o non essere appropriata a seconda dello stile grafico e della direzione del gioco.

Un modello visualizzato con e senza una mappa normale
Figura 16. Un modello visualizzato senza una mappa normale (a sinistra) e lo stesso modello visualizzato con una mappa normale (al centro) e la texture normale (a destra).

Le mappe normali comportano un costo in termini di prestazioni e devono essere utilizzate con parsimonia sui dispositivi di fascia inferiore. La mappa normale richiede una texture aggiuntiva, il che comporta un ulteriore campionamento delle texture e i calcoli dello strumento per l'identificazione dei frammenti.

Normali best practice per le mappe

Di seguito sono riportate alcune best practice per la normale creazione di mappe:

Utilizza una gabbia

Una gabbia è una versione più grande o spinta fuori del tuo modello a poligono basso. Deve includere il modello a poligono alto per funzionare bene durante la normale cottura della mappa. La gabbia viene utilizzata per limitare la distanza del raggio d'azione durante la normale cottura della mappa e aiuta a evitare problemi con le normali cuciture divisa sulla mappa normale.

Una gabbia che circonda la maglia poligonale bassa
Figura 17. Una gabbia che circonda la maglia poligonale bassa.
Un modello visualizzato utilizzando una mappa normale con e senza una gabbia
Figura 18. Il rendering di un modello mediante una mappa normale generata con una gabbia (a sinistra) rispetto a un modello il cui rendering è stato eseguito utilizzando una mappa normale generata senza una gabbia (a destra).

Corrispondenza di forno per nome mesh

Se il tuo software di cottura lo supporta, esegui la corrispondenza in base al nome del mesh. Questa funzione riduce il problema della normale proiezione errata della mappa. Quando gli oggetti sono troppo vicini tra loro, potrebbero proiettare inaspettatamente la loro mappa normale sulla faccia sbagliata. La corrispondenza per nome mesh garantisce che la cottura venga eseguita solo sulla superficie corretta. Per ulteriori informazioni su questa funzionalità in Substance Painter, visita questa pagina. Per ulteriori informazioni su questa funzionalità in Marmoset Toolbag, visita questa pagina.

Fai esplodere la rete mesh

Se non riesci a far corrispondere il nome mesh durante la cottura, prova a far esplodere la mesh. L'esplosione della mesh allontana le parti l'una dall'altra in modo che la mappa normale non venga proiettata sulla superficie sbagliata. Se stai cuocendo anche per una cottura in ambienti ambient, potrebbe essere necessario eseguirla separatamente con una rete non esplosa.

Una rete esplosa per la normale cottura delle mappe
Figura 19. Una rete mesh esplosa per la normale creazione di mappe

Riduci al minimo le cuciture

I raggi UV continui sui bordi duri rendono più visibili le cuciture, i raggi UV spaccati sui bordi duri per ridurre al minimo questo effetto. Quando imposti gruppi di livellamento, come regola generale mantieni l'angolo al di sotto di 90 gradi. Le cuciture UV devono avere un gruppo di levigatura diverso sui triangoli.