Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo si basa sulle raccomandazioni sulle prestazioni per la realtà mista, ma si concentra sui miglioramenti specifici di Unity.
Di recente è stata rilasciata un'applicazione denominata Quality Fundamentals che illustra i problemi comuni di prestazioni, progettazione e ambiente e le soluzioni per le app HoloLens 2. Questa app è un'ottima demo visiva per i contenuti che seguono.
Usare le impostazioni consigliate per il progetto Unity
Il primo passaggio più importante quando si ottimizzano le prestazioni delle app di realtà mista in Unity è assicurarsi di usare le impostazioni di ambiente consigliate per Unity. Questo articolo contiene contenuto con alcune delle configurazioni di scena più importanti per la creazione di app di realtà mista performanti. La sezione seguente evidenzia alcune di queste impostazioni consigliate.
Come creare profili con Unity
Unity fornisce Unity Profiler integrato, una risorsa ottimale per raccogliere informazioni preziose sulle prestazioni di un'app specifica. Sebbene sia possibile eseguire il profiler nell'editor, queste metriche non rappresentano il vero ambiente di runtime, quindi i risultati devono essere usati con cautela. Profila in remoto la tua applicazione mentre è in esecuzione sul dispositivo per ottenere le informazioni più accurate e fruibili.
Unity offre un'ottima documentazione per:
- Come connettere il profiler Unity alle applicazioni UWP in remoto
- Come diagnosticare in modo efficace i problemi di prestazioni con Unity Profiler
Profilatura GPU
Profiler di Unity
Con Unity Profiler connesso e dopo aver aggiunto il profiler GPU (vedere Aggiungi profiler nell'angolo in alto a destra), è possibile vedere quanto tempo viene trascorso rispettivamente sulla CPU & sulla GPU al centro del profiler. Ciò consente allo sviluppatore di ottenere una rapida approssimazione se l'applicazione è associata a CPU o GPU.
Nota
Per utilizzare la profilazione GPU, è necessario disabilitare i processi grafici nelle impostazioni di Unity Player. Per altri dettagli, vedere il modulo Profiler utilizzo GPU di Unity.
Debugger Unity Frame
Frame Debugger di Unity è anche uno strumento potente e perspicace da usare. Ti dà una buona panoramica di ciò che la GPU sta facendo in ogni fotogramma. Gli elementi a cui prestare attenzione sono altri obiettivi di rendering e comandi blit da copiare tra di essi, in quanto sono costosi su HoloLens. Idealmente, in HoloLens non devono essere utilizzate destinazioni di rendering esterne allo schermo. Questi vengono aggiunti quando si abilitano costose funzionalità di rendering (ad esempio MSAA, HDR o effetti a schermo intero come la fioritura) che dovrebbero essere evitate.
Sovrapposizione della frequenza dei fotogrammi di HoloLens
La pagina Prestazioni di sistema di Device Portal contiene un riepilogo delle prestazioni della CPU e della GPU del dispositivo. Puoi abilitare Visualizza contatore frame rate nell'headset e Visualizza grafico frame rate nell'headset. Queste opzioni abilitano rispettivamente un contatore FPS e un grafico che forniscono un feedback immediato in qualsiasi applicazione in esecuzione sul dispositivo.
PIX
PIX può essere utilizzato anche per profilare le applicazioni Unity. Sono disponibili anche istruzioni dettagliate su come usare e installare PIX per HoloLens 2. In una build di sviluppo, gli stessi ambiti visualizzati nel Frame Debugger di Unity verranno visualizzati anche in PIX e potranno essere ispezionati e profilati in modo più dettagliato.
Nota
Unity consente di modificare facilmente la risoluzione di destinazione del rendering dell'applicazione in fase di esecuzione tramite la proprietà XRSettings.renderViewportScale . L'immagine finale presentata sul dispositivo ha una risoluzione fissa. La piattaforma campiona l'output a risoluzione più bassa per creare un'immagine a risoluzione più alta per il rendering sugli schermi.
UnityEngine.XR.XRSettings.renderViewportScale = 0.7f;
Consigli sulle prestazioni della CPU
Il contenuto seguente illustra procedure di prestazioni più approfondite, destinate in particolare allo sviluppo di Unity & C#.
Riferimenti alla cache
È consigliabile memorizzare nella cache i riferimenti a tutti i componenti pertinenti e agli oggetti GameObject al momento dell'inizializzazione perché le chiamate di funzione ripetute come GetComponent<T>() e Camera.main sono più costose rispetto al costo di memoria per archiviare un puntatore. Camera.main utilizza solo FindGameObjectsWithTag() sotto, che cerca in modo costoso nel grafico della scena un oggetto fotocamera con il tag "MainCamera ".
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
private Camera cam;
private CustomComponent comp;
void Start()
{
cam = Camera.main;
comp = GetComponent<CustomComponent>();
}
void Update()
{
// Good
this.transform.position = cam.transform.position + cam.transform.forward * 10.0f;
// Bad
this.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 10.0f;
// Good
comp.DoSomethingAwesome();
// Bad
GetComponent<CustomComponent>().DoSomethingAwesome();
}
}
Nota
Evitare GetComponent(string)
Quando si usa GetComponent(), ci sono una manciata di overload diversi. È importante usare sempre le implementazioni basate su tipo e mai l'overload di ricerca basato su stringhe. La ricerca per stringa nella scena è più costosa della ricerca per tipo.
(Buono) Componente: GetComponent(Type type)
(Buono) T GetComponent<T>()
(Cattivo) Componente GetComponent(string)>
Evitare operazioni costose
Evitare l'uso di LINQ
Sebbene LINQ possa essere pulito e facile da leggere e scrivere, in genere richiede più calcolo e memoria rispetto a quando si scrive manualmente l'algoritmo.
// Example Code using System.Linq; List<int> data = new List<int>(); data.Any(x => x > 10); var result = from x in data where x > 10 select x;API comuni per unità
Alcune API Unity, sebbene utili, possono essere costose da eseguire. La maggior parte di queste comporta la ricerca di un elenco di GameObject corrispondenti nell'intero grafico della scena. Queste operazioni possono essere generalmente evitate memorizzando nella cache i riferimenti o implementando un componente di gestione per GameObjects per tenere traccia dei riferimenti in fase di esecuzione.
GameObject.SendMessage() GameObject.BroadcastMessage() UnityEngine.Object.Find() UnityEngine.Object.FindWithTag() UnityEngine.Object.FindObjectOfType() UnityEngine.Object.FindObjectsOfType() UnityEngine.Object.FindGameObjectsWithTag() UnityEngine.Object.FindGameObjectsWithTag()
Nota
SendMessage() e BroadcastMessage() dovrebbero essere eliminati a tutti i costi. Queste funzioni possono essere dell'ordine di 1000 volte più lente delle chiamate di funzione dirette.
Attenzione alla boxe
La boxing è un concetto fondamentale del linguaggio e del runtime C#. È il processo di wrapping di variabili
chartipizzate con valori come ,int, ,boolecc. in variabili tipizzate di riferimento. Quando una variabile tipizzata viene "inscatolata", viene racchiusa in unSystem.Object, che viene archiviato nell'heap gestito. La memoria viene allocata e alla fine, una volta smaltita, deve essere elaborata dal Garbage Collector. Queste allocazioni e deallocazioni comportano un costo in termini di prestazioni e in molti scenari non sono necessarie o possono essere facilmente sostituite da un'alternativa meno costosa.Per evitare la boxing, accertarsi che le variabili, i campi e le proprietà in cui si memorizzano i tipi numerici e le strutture (tra cui
Nullable<T>) siano tipizzati come tipi specifici, ad esempioint,float?oMyStruct, anziché usare object. Se si inseriscono questi oggetti in un elenco, assicurarsi di usare un elenco fortemente tipizzato comeList<int>piuttosto cheList<object>oArrayList.Esempio di boxe in C#
// boolean value type is boxed into object boxedMyVar on the heap bool myVar = true; object boxedMyVar = myVar;
Ripetizione di percorsi di codice
Tutte le funzioni di callback ripetute di Unity (ad esempio Update) che vengono eseguite molte volte al secondo e/o in ogni frame devono essere scritte con attenzione. Qualsiasi operazione costosa qui ha un impatto enorme e costante sulle prestazioni.
Funzioni di callback vuote
Anche se il codice seguente può sembrare innocente da lasciare nell'applicazione, soprattutto perché ogni script di Unity viene inizializzato automaticamente con un metodo Update, questi callback vuoti possono diventare costosi. Unity opera avanti e indietro tra un limite di codice non gestito e gestito, tra il codice UnityEngine e il codice dell'applicazione. Il cambio di contesto su questo bridge è piuttosto costoso, anche se non c'è nulla da eseguire. Ciò diventa particolarmente problematico se l'app ha centinaia di GameObject con componenti con callback Unity ripetuti vuoti.
void Update() { }
Nota
Update() è la manifestazione più comune di questo problema di prestazioni, ma altri callback Unity ripetuti, ad esempio i seguenti, possono essere altrettanto negativi, se non peggiori: FixedUpdate(), LateUpdate(), OnPostRender", OnPreRender(), OnRenderImage(), ecc.
Operazioni per favorire l'esecuzione una volta per frame
Le API Unity seguenti sono operazioni comuni per molte app olografiche. Anche se non sempre possibile, i risultati di queste funzioni possono essere in genere calcolati una volta e i risultati possono essere riutilizzati nell'applicazione per un determinato frame.
- È buona norma avere una classe o un servizio Singleton dedicato per gestire il raycast dello sguardo nella scena e quindi riutilizzare questo risultato in tutti gli altri componenti della scena, invece di eseguire operazioni Raycast ripetute e identiche da ciascun componente. Alcune applicazioni possono richiedere raycast da origini diverse o contro LayerMask diversi.
UnityEngine.Physics.Raycast() UnityEngine.Physics.RaycastAll()- Evitare operazioni GetComponent() in callback Unity ripetuti come Update() memorizzando nella cache i riferimenti in Start() o Awake()
UnityEngine.Object.GetComponent()- È buona norma creare un'istanza di tutti gli oggetti, se possibile, al momento dell'inizializzazione e usare il pool di oggetti per riciclare e riutilizzare i GameObject durante il runtime dell'applicazione
UnityEngine.Object.Instantiate()Evita interfacce e costrutti virtuali
Richiamare chiamate di funzione tramite interfacce rispetto a oggetti diretti o chiamare funzioni virtuali può spesso essere molto più costoso rispetto all'uso di costrutti diretti o chiamate di funzione dirette. Se la funzione o l'interfaccia virtuale non è necessaria, deve essere rimossa. Tuttavia, l'impatto sulle prestazioni di questi approcci vale il compromesso se l'utilizzo semplifica la collaborazione allo sviluppo, la leggibilità del codice e la manutenibilità del codice.
In generale, la raccomandazione è di non contrassegnare campi e funzioni come virtuali a meno che non si preveda chiaramente che questo membro debba essere sovrascritto. Si dovrebbe prestare particolare attenzione ai percorsi di codice ad alta frequenza che vengono chiamati molte volte per fotogramma o anche una volta per fotogramma, come un
UpdateUI()metodo.Evita di passare le strutture per valore
A differenza delle classi, le strutture sono tipi di valore e quando vengono passate direttamente a una funzione, il loro contenuto viene copiato in un'istanza appena creata. Questa copia aggiunge il costo della CPU e più memoria sullo stack. Per le strutture piccole, l'effetto è minimo e quindi accettabile. Tuttavia, per le funzioni richiamate ripetutamente ogni frame e le funzioni che accettano strutture di grandi dimensioni, se possibile modificare la definizione della funzione in modo che passi per riferimento. Altre informazioni sono disponibili qui
Varie
Fisica
In generale, il modo più semplice per migliorare la fisica è limitare la quantità di tempo dedicato alla fisica o il numero di iterazioni al secondo. Ciò riduce l'accuratezza della simulazione. Vedi TimeManager in Unity.
I tipi di collisori in Unity hanno caratteristiche prestazionali molto diverse. L'ordine seguente elenca i collisori più performanti e i collisori meno performanti da sinistra a destra. È importante evitare i Mesh Collider, che sono sostanzialmente più costosi dei collisori primitivi.
Sphere < Capsule < Box <<< Mesh (convesso) < Mesh (non convesso)
Azioni
Disabilita le animazioni inattive disabilitando il componente Animator (disabilitare l'oggetto di gioco non avrà lo stesso effetto). Evita i modelli di progettazione in cui un animatore si trova in un ciclo impostando un valore sullo stesso valore. C'è un notevole sovraccarico per questa tecnica, senza alcun effetto sull'applicazione. Scopri di più qui.
Algoritmi complessi
Se la tua applicazione utilizza algoritmi complessi come la cinematica inversa, la ricerca del percorso, ecc., cerca di trovare un approccio più semplice o regola le impostazioni pertinenti per le loro prestazioni.
Consigli sulle prestazioni da CPU a GPU
Generalmente, le prestazioni da CPU a GPU dipendono dalle chiamate di disegno inviate alla scheda grafica. Per migliorare le prestazioni, le chiamate di estrazione devono essere strategicamente a) ridotte o b) ristrutturate per ottenere risultati ottimali. Poiché le chiamate di estrazione stesse richiedono molte risorse, ridurle ridurrà il lavoro complessivo richiesto. Inoltre, i cambiamenti di stato tra le chiamate di disegno richiedono costosi passaggi di convalida e traduzione nel driver grafico e, pertanto, la ristrutturazione delle chiamate di disegno dell'applicazione per limitare i cambiamenti di stato (ad esempio materiali diversi, ecc.) può aumentare le prestazioni.
Unity ha un ottimo articolo che fornisce una panoramica e si tuffa nelle chiamate di estrazione in batch per la loro piattaforma.
Rendering con istanza a passaggio singolo
Il rendering con istanza a passaggio singolo in Unity consente di ridurre le chiamate di estrazione per ciascun occhio a una chiamata di estrazione con istanza. A causa della coerenza della cache tra due chiamate di disegno, c'è anche un miglioramento delle prestazioni della GPU.
Per abilitare questa funzionalità nel progetto Unity
- Apri le impostazioni di OpenXR (vai a Modifica>impostazioni> progettoGestione plug-in> XROpenXR).
- Selezionare Istanza a passaggio singolo dal menu a discesa Modalità di rendering .
Leggi gli articoli seguenti di Unity per informazioni dettagliate su questo approccio di rendering.
- Come massimizzare le prestazioni di realtà aumentata e virtuale con il rendering stereo avanzato
- Istanza a passaggio singolo
Nota
Un problema comune con il rendering con istanze a passaggio singolo si verifica se gli sviluppatori hanno già shader personalizzati esistenti non scritti per l'istanza. Dopo aver abilitato questa funzionalità, gli sviluppatori potrebbero notare che alcuni GameObject eseguono il rendering solo in un occhio. Ciò è dovuto al fatto che gli shader personalizzati associati non hanno le proprietà appropriate per l'istanza.
Batch statico
Unity è in grado di eseguire il batch di molti oggetti statici per ridurre le chiamate di disegno alla GPU. L'invio in batch statico funziona per la maggior parte degli oggetti renderer in Unity che 1) condividono lo stesso materiale e 2) sono tutti contrassegnati come statici (seleziona un oggetto in Unity e seleziona la casella di controllo in alto a destra dell'ispezione). I GameObject contrassegnati come statici non possono essere spostati nel runtime dell'applicazione. Pertanto, l'invio in batch statico può risultare difficile da applicare in HoloLens, in cui praticamente ogni oggetto deve essere posizionato, spostato, ridimensionato e così via. Per i visori VR immersivi, l'invio statico in batch può ridurre notevolmente le chiamate di pescaggio e quindi migliorare le prestazioni.
Per altri dettagli, vedere Static Batching in Draw Call Batching in Unity .
Batch dinamico
Poiché è problematico contrassegnare gli oggetti come statici per lo sviluppo di HoloLens, l'invio dinamico in batch può essere un ottimo strumento per compensare questa mancanza. Può essere utile anche su visori VR immersivi. Tuttavia, l'invio dinamico in batch in Unity può essere difficile da abilitare perché i GameObject devono a) condividere lo stesso materiale e b) soddisfare un lungo elenco di altri criteri.
Per l'elenco completo, vedere Dynamic Batching in Draw Call Batching in Unity . Più comunemente, i GameObject non sono più validi per essere raggruppati in batch in modo dinamico, perché i dati mesh associati non possono essere più di 300 vertici.
Altre tecniche
L'invio in batch può verificarsi solo se più GameObject sono in grado di condividere lo stesso materiale. In genere, questo viene bloccato dalla necessità per GameObjects di avere una texture univoca per il rispettivo materiale. È comune combinare le texture in un'unica grande texture, un metodo noto come atlantizzazione delle texture.
Inoltre, è preferibile combinare le mesh in un unico GameObject ove possibile e ragionevole. Ogni renderer in Unity ha la relativa chiamata di disegno associata rispetto all'invio di una mesh combinata in un unico renderer.
Nota
La modifica delle proprietà di Renderer.material in fase di esecuzione crea una copia del materiale e quindi potrebbe interrompere il batching. Usa Renderer.sharedMaterial per modificare le proprietà dei materiali condivisi tra GameObjects.
Consigli sulle prestazioni della GPU
Larghezza di banda e velocità di riempimento
Durante il rendering di un frame sulla GPU, un'applicazione è associata alla larghezza di banda della memoria o alla velocità di riempimento.
-
La larghezza di banda della memoria è la velocità di lettura e scrittura che la GPU può eseguire dalla memoria
- In Unity, modifica la qualità della texture in Modifica>impostazioni> progettoImpostazioni qualità.
-
Il tasso di riempimento si riferisce ai pixel che possono essere disegnati al secondo dalla GPU.
- In Unity usare la proprietà XRSettings.renderViewportScale .
Ottimizzare la condivisione del buffer di profondità
È consigliabile abilitare la condivisione del buffer di profondità per ottimizzare la stabilità dell'ologramma. Quando si abilita la riproiezione in fase avanzata basata sulla profondità con questa impostazione, è consigliabile selezionare il formato di profondità a 16 bit anziché il formato di profondità a 24 bit . I buffer di profondità a 16 bit ridurranno drasticamente la larghezza di banda (e quindi la potenza) associata al traffico del buffer di profondità. Questo può essere un grande miglioramento sia nella riduzione della potenza che nelle prestazioni. Tuttavia, ci sono due possibili risultati negativi usando il formato di profondità a 16 bit.
Combattimento Z
La fedeltà ridotta dell'intervallo di profondità rende più probabile che si verifichi z-fighting a 16 bit rispetto a 24 bit. Per evitare questi artefatti, modifica i piani di ritaglio vicino/lontano della fotocamera Unity per tenere conto della precisione inferiore. Per le applicazioni basate su HoloLens, un piano di ritaglio lontano di 50 m invece dei 1.000 m predefiniti di Unity può in genere eliminare qualsiasi combattimento z.
Buffer stencil disabilitato
Quando Unity crea una texture di rendering con profondità di 16 bit, non viene creato alcun buffer di stencil. Selezionando il formato profondità 24 bit, come descritto nella documentazione di Unity, verranno creati uno z-buffer a 24 bit e uno stencil buffer a 8 bit (se la versione a 32 bit è applicabile in un dispositivo (ad esempio, HoloLens), come in genere accade).
Evitare gli effetti a schermo intero
Le tecniche che operano a schermo intero possono essere costose poiché il loro ordine di grandezza è di milioni di operazioni per fotogramma. È consigliabile evitare effetti di post-elaborazione come anti-aliasing, bloom e altro.
Impostazioni di illuminazione ottimali
L'illuminazione globale in tempo reale in Unity può fornire risultati visivi eccezionali, ma comporta costosi calcoli di illuminazione. È consigliabile disabilitare l'illuminazione globale in tempo reale per ogni file di scena di Unity tramitele impostazioni> di illuminazionedel rendering delle>finestre> Deselezionare l'illuminazione globale in tempo reale.
Inoltre, si consiglia di disabilitare tutta la proiezione di ombre in quanto questi aggiungono anche costosi passaggi GPU su una scena Unity. Le ombre possono essere disabilitate per ogni luce, ma possono anche essere controllate in modo olistico tramite le impostazioni di qualità.
Modifica>Impostazioni progetto, quindi seleziona la categoria >Qualità e seleziona Qualità bassa per la piattaforma UWP. Si può anche semplicemente impostare la proprietà Ombre su Disabilita ombre.
Ti consigliamo di usare l'illuminazione baked con i tuoi modelli in Unity.
Ridurre il numero di poligoni
Il numero di poligoni viene ridotto di
- Rimozione di oggetti da una scena
- Decimazione delle risorse, che riduce il numero di poligoni per una data mesh
- Implementazione di un sistema Level of Detail (LOD) nell'applicazione, che esegue il rendering di oggetti lontani con una versione poligonale inferiore della stessa geometria
Informazioni sugli shader in Unity
Un'approssimazione semplice per confrontare le prestazioni degli shader consiste nell'identificare il numero medio di operazioni eseguite ciascuno in fase di esecuzione. Questa operazione può essere eseguita facilmente in Unity.
Seleziona la risorsa shader o seleziona un materiale, quindi nell'angolo in alto a destra della finestra di controllo. Seleziona l'icona a forma di ingranaggio seguita da "Seleziona shader".
Con l'asset shader selezionato, seleziona il pulsante "Compila e mostra codice" nella finestra di controllo.
Dopo la compilazione, cerca la sezione delle statistiche nei risultati con il numero di operazioni diverse sia per il vertex che per il pixel shader (Nota: i pixel shader sono spesso chiamati anche fragment shader).
Ottimizza i pixel shader
Esaminando i risultati delle statistiche compilati usando il metodo precedente, il fragment shader eseguirà in genere più operazioni rispetto al vertex shader, in media. Il fragment shader, noto anche come pixel shader, viene eseguito per pixel sull'output dello schermo, mentre il vertex shader viene eseguito solo per vertice di tutte le mesh disegnate sullo schermo.
Pertanto, non solo i fragment shader hanno più istruzioni dei vertex shader a causa di tutti i calcoli di illuminazione, ma i fragment shader vengono quasi sempre eseguiti su un set di dati più grande. Ad esempio, se l'output dello schermo è un'immagine 2k per 2k, il fragment shader può essere eseguito 2.000*2.000 = 4.000.000 di volte. Se si esegue il rendering di due occhi, questo numero raddoppia perché ci sono due schermi. Se un'applicazione di realtà mista ha più passaggi, effetti di post-elaborazione a schermo intero o rendering di più mesh nello stesso pixel, questo numero aumenta notevolmente.
Pertanto, la riduzione del numero di operazioni nel fragment shader può in genere offrire miglioramenti delle prestazioni molto maggiori rispetto alle ottimizzazioni nel vertex shader.
Alternative shader Unity Standard
Invece di utilizzare un Physically Based Rendering (PBR) o un altro shader di alta qualità, cerca di utilizzare uno shader più performante ed economico. Il toolkit per realtà mista fornisce lo shader standard MRTK ottimizzato per i progetti di realtà mista.
Unity fornisce anche opzioni di shader non illuminato, vertice, diffuso e altre opzioni di shader semplificate che sono più veloci rispetto allo shader Unity Standard. Per ulteriori informazioni, vedere Utilizzo e prestazioni degli shader predefiniti.
Precaricamento shader
Usa il precaricamento dello shader e altri accorgimenti per ottimizzare il tempo di caricamento dello shader. In particolare, il precaricamento dello shader significa che non si verificheranno intoppi dovuti alla compilazione dello shader di runtime.
Limita lo scoperto
In Unity, è possibile visualizzare l'overdraw per la propria scena, attivando o disattivando il menu della modalità di disegno nell'angolo in alto a sinistra della vista Scena e selezionando Overdraw.
In genere, l'overdraw può essere mitigato eliminando gli oggetti in anticipo prima che vengano inviati alla GPU. Unity fornisce informazioni dettagliate sull'implementazione dell'eliminazione dell'occlusione per il motore.
Suggerimenti per la memoria
Le operazioni di allocazione & deallocazione della memoria eccessive possono avere effetti negativi sull'applicazione olografica, con conseguente prestazioni incoerenti, fotogrammi bloccati e altri comportamenti dannosi. È particolarmente importante comprendere le considerazioni sulla memoria quando si sviluppa in Unity poiché la gestione della memoria è controllata dal Garbage Collector.
Garbage Collection
Le app olografiche perdono il tempo di elaborazione del calcolo a favore del Garbage Collector (GC) quando il GC viene attivato per analizzare gli oggetti che non sono più nell'ambito durante l'esecuzione e la relativa memoria deve essere rilasciata, in modo che possa essere resa disponibile per il riutilizzo. Le allocazioni e le deallocazioni costanti richiedono in genere che il Garbage Collector venga eseguito più frequentemente, danneggiando così le prestazioni e l'esperienza utente.
Una delle procedure più comuni che porta a un'eccessiva operazione di Garbage Collection è non memorizzare nella cache i riferimenti a componenti e classi nello sviluppo di Unity. Tutti i riferimenti devono essere acquisiti durante Start() o Awake() e riutilizzati in funzioni successive come Update() o LateUpdate().
Altri suggerimenti rapidi:
- Usare la classe StringBuilder C# per compilare dinamicamente stringhe complesse in fase di esecuzione.
- Rimuovere le chiamate a Debug.Log() quando non sono più necessarie, poiché vengono ancora eseguite in tutte le versioni della build di un'app
- Se l'app olografica richiede in genere molta memoria, è consigliabile chiamare System.GC.Collect() durante le fasi di caricamento, ad esempio quando si presenta una schermata di caricamento o di transizione.
Pooling di oggetti
Il pooling di oggetti è una tecnica popolare per ridurre il costo dell'allocazione e della deallocazione continua degli oggetti. Questa operazione viene eseguita allocando un grande pool di oggetti identici e riutilizzando le istanze inattive disponibili di questo pool invece di generare ed eliminare costantemente oggetti nel tempo. I pool di oggetti sono ideali per i componenti riutilizzabili che hanno una durata variabile durante un'app.
Prestazioni di avvio
Prendi in considerazione l'idea di iniziare l'app con una scena più piccola, quindi di usare SceneManager.LoadSceneAsync per caricare il resto della scena. Ciò consente all'app di raggiungere uno stato interattivo il più rapidamente possibile. È possibile che si verifichi un picco della CPU durante l'attivazione della nuova scena e che il contenuto di cui viene eseguito il rendering possa causare interruzioni o intoppi. Un modo per risolvere il problema consiste nell'impostare la proprietà AsyncOperation.allowSceneActivation su "false" nella scena in fase di caricamento, attendere il caricamento della scena, cancellare lo schermo in nero e quindi impostarla nuovamente su "true" per completare l'attivazione della scena.
Tenere presente che durante il caricamento della scena di avvio, viene visualizzata all'utente la schermata iniziale olografica.