Intro

La puntata di questa settimana dell’Around the Verse è incentrata sull’aggiornamento di sviluppo del progetto, comprensivo di un segmento dedicato alle ottimizzazioni per il miglioramento delle prestazioni di Star Citizen.

 

Aggiornamenti di Sviluppo

Ricky Jutley – Produttore Senior

Team della UI

Il team della UI sta lavorando ai nuovi ologrammi di status dei veicoli, che permettono di tenere sotto controllo lo stato della propria nave e di quella bersaglio.
La vecchia tecnologia, risalente ai tempi della 1.prima versione dell’Arena Commander, trattava gli ologrammi come delle entità a parte, separate dal velivolo a cui si riferivano. Il nuovo sistema, invece, costituisce un’accurata rappresentazione della nave bersaglio, ad essa direttamente collegata e realizzata mediante la tecnologia della Renderizzazione su Texture. La silhoutte viene riprodotta selezionando soltanto una parte degli snodi di rendering del velivolo, a cui poi vengono sovrapposti degli shader colorati che descrivono lo stato di danneggiamento dei suoi componenti.
In tal modo, è possibile mantenere aggiornato il giocatore sulle condizioni della propria nave e di quella nemica, limitando il peso di renderizzazione di questi modelli.

Prestazioni_Ottimizzazioni - aggiornamenti_2.jpg

Un vantaggio aggiuntivo di questa tecnologia consiste nel fatto che non è vincolata esclusivamente al visore del pilota. Gli ologrammi potranno essere mostrati anche sugli schermi multi funzione (MFD) delle navi.
Ciò varrà anche per i filmati associati alle videochiamate in gioco, i cosiddetti Comm. Questi sono realizzate sfruttando sempre la tecnologia della Renderizzazione su Texture e rappresentano una corretta ed accurata riproduzione della scena di gioco.

Prestazioni_Ottimizzazioni - aggiornamenti_1.jpg

La 3.1.0 vedrà la prima implementazione di questa nuova tecnologia degli ologrammi, che godrà di una serie di funzionalità aggiuntive. Tramite gli MFD sarà possibile visualizzare la nave obiettivo, o la propria, da angoli differenti, che verranno quindi riprodotti allo stesso modo anche sul visore. La modalità standard rimarrà quella live, che mostrerà il velivolo obiettivo nella stessa orientazione da cui la vedrà il pilota.

Un altro miglioramento presente nella 3.1.0 è la maniera in cui vengono trattati e gestiti gli schermi delle navi.
In precedenza, ogni abitacolo aveva un numero fisso, immodificabile e predefinito di schermi, come quelli degli armamenti, l’energia, il segnale generato e via dicendo. In futuro, gli utenti avranno la possibilità di aggiungere dei nuovi schermi o rimuovere alcuni di quelli già presenti, così da personalizzare l’abitacolo.
La primissima applicazione di questo sistema è costituito dalla possibilità di connettere parte degli schermi dell’abitacolo al visore per rappresentarvi informazioni aggiuntive, oppure rimuovere quelli presenti.

Prestazioni_Ottimizzazioni - aggiornamenti_4.jpg

Team Pianeti Procedurali

Il team è stato impegnato a modificare la tecnologia dei pianeti procedurali e quella di rendering.
Il nuovo sistema presenta una migliore ripartizione in canali differenti della renderizzazione, della distribuzione dei biomi procedurali e del colour blending. Ciò permetterà al motore di gioco di gestire in maniera indipendente e contemporanea ciascuna di queste attività, senza che entrino in conflitto tra loro. Il vantaggio immediato di questa modifica consisterà in una migliore rappresentazione degli ambienti planetari ed in più fluide transizioni pianeta/spazio. In aggiunta, sono stati migliorati gli strumenti di posizionamento degli avamposti sui corpi celesti, che adesso vengono automaticamente implementati negli ambienti procedurali.
Queste novità faranno il loro debutto con l’aggiornamento 3.1 di prossima uscita.

Prestazioni_Ottimizzazioni - aggiornamenti_5.jpg

Team Ambientale

Continuano i lavori sulle stazioni di rifornimento.
I compiti attuali riguardano principalmente le rifiniture esterne e l’assemblaggio degli hangar comuni. Per quanto riguarda invece gli interni, lo strumento di generazione procedurale degli ambienti ha raggiunto una maturità sufficiente da essere in grado di generare con successo centinaia di combinazioni differenti di stanze con una discreta varietà di composizione. Il team continuerà a migliorarlo per permettere il suo utilizzo anche in altri ambiti.

Prestazioni_Ottimizzazioni - aggiornamenti_6.jpg

Team degli effetti visivi

L’Aegis Reclaimer, la Tumbril Cyclone, la Anvil Terrapin e la MISC Razor sono ormai prossime al completamento. Il team degli effetti visivi sta realizzando tutti i VFX mancanti per questi vascelli.
Inoltre, è in corso la revisione degli effetti di impatto di armi come il fucile Gemini R97 ed il railgun Scourge.

Prestazioni_Ottimizzazioni - aggiornamenti_7.jpg

Team delle Funzionalità

Sono stati completati i lavori previsti per le app del Manager dei Veicoli (VMA) e quello personale (PMA), le cui modifiche sono attualmente in fase di test in vista del loro rilascio con la 3.1.

Allo stesso tempo, è in corso la revisione della schermata di personalizzazione dell’equipaggiamento di Star Marine. Come già avvenuto con l’Arena Commander, questa sezione sarà rimpiazzata con le stesse risorse utilizzate per il PMA, così da uniformare i sistemi e l’esperienza utente a questi connessi. Così facendo, sarà anche più semplice per gli sviluppatori migliorare e sistemare questi elementi, dato che saranno condivisi tra PU e Star Marine.

Prestazioni_Ottimizzazioni - aggiornamenti_8.jpg

A livello di funzionalità, questo cambiamento implica che gli utenti avranno la possibilità di equipaggiare svariate combinazioni di armature differenti. Ciò conferirà una componente più tattica alla selezione dell’equipaggiamento, dato che la pesantezza delle corazzature indossate avrà svariate conseguenze di gameplay.

Il codice necessario per l’implementazione di queste modifiche è già pronto. Il team della UI dovrà però modificare l’interfaccia per portarla al livello qualitativo standard di Star Citizen. Tutto questo sarà rilasciato assieme all’aggiornamento 3.1.

Team della UI

Il team sta lavorando ad una serie di miglioramenti previsti per il mobiGlas e le sue app.
Questi vanno dall’implementazione di un nuovo schema organizzativo delle informazioni, all’incremento dello spazio occupato dalle schermate del mobiGlas su schermo, così da renderlo più leggibile. Inoltre, stanno apportando delle modifiche alle regole di rendering ed agli shader usati per il mobiGlas, così da migliorarne la visibilità.

Team Artistico Tecnico

Continuano i lavori riguardanti il sistema di Personalizzazione dei Personaggi.
Il team di LA è stato impegnato a migliorare le animazione di idle del modello di anteprima del personaggio, così da renderlo più vivo e credibile. Parallelamente, è stata incrementata la qualità visiva del modello della testa e del corpo ed è stata eliminata la netta separazione precedentemente presente tra le texture dei due.
La telecamera ha ricevuto una serie di miglioramenti riguardanti la profondità e l’ampiezza di campo, nonché la sua angolazione, così da dare maggior risalto al personaggio.
Infine, sono state implementate le icone provvisorie associate alle varie possibilità di personalizzazione, in attesa che venga integrato il codice necessario per la rappresentazione della loro versione finale.

Prestazioni_Ottimizzazioni - aggiornamenti_9.jpg

Nel corso di queste mansioni, il team ha scoperto svariati bug che sono stati debitamente ricontrollati e rimossi.
Tra di essi, si annoverano problemi relativi alla rapida selezione o deselezione delle opzioni di personalizzazione. Nonché inconsistenze riguardanti la Persistenza ed il mancato salvataggio delle caratteristiche dell’avatar.

Team di Gameplay

I radiofari di servizio, la tecnologia che permetterà agli utenti di generare contenuti di gioco, è in fase di sviluppo.
La prima versione di questo sistema sarà rilasciata con l’aggiornamento 3.1 e permetterà di creare ed accettare missioni di trasporto ed assistenza al combattimento. I giocatori potranno pubblicare queste richieste direttamente dal Manager dei Contratti. Nel momento in cui la missione sarà stata accettata, sulla UI comparirà un indicatore di destinazione ed entrambe le controparti potranno vedere la posizione dell’altra per l’intera durata del contratto. Esso potrà essere cancellato in qualsiasi momento, ma alla sua conclusione entrambi i giocatori potranno assegnare un voto all’altro.

Al momento sono stati riscontrati dei problemi durante l’implementazione della tecnologia nei servizi di backend. Essi riguardano principalmente l’integrazione con il sistema della Diffusione, che gestisce i server di gioco e mantiene i vari task thread safe.

Team dei Personaggi

Il team è stato impegnato a risolvere una serie di problemi relativi agli elmetti, come il fatto che le luci del casco venissero riprodotte anche in sua assenza. Oppure la capacità di indossare un cappellino assieme all’elmetto.

 

Ottimizzazioni e Prestazioni

Con Mark Abent – Ingegnere Capo del Gameplay
Christopher Bolte – Programmatore del Motore di Gioco
Clive Johnson – Programmatore Capo della Rete
Matthew Intrieri – Artista Tecnico delle Navi
Robert Johnson – Programmatore Capo del Gameplay

Star Citizen sarà un gioco estremamente complesso.
In ogni momento, da qualche parte nell’universo potranno essere presenti centinaia o migliaia di entità, ciascuna delle quali sarà impegnata in una serie di attività differenti. Alcune di esse potrebbero avere delle logiche complesse, le quali potrebbero richiedere l’esecuzione contemporanea di più azioni. Per fare ciò, ciascuna di queste entità avrà bisogno di inviare o richiedere informazioni al server, le quali dovranno essere elaborate e renderizzate prima che il gioco possa passare al frame successivo.

Questo carico è uno degli aspetti più complicati di Star Citizen, nonché quello responsabile di buona parte delle problematiche riscontrate negli ultimi anni. Per questo motivo, per tutto il 2018 verranno effettuate svariate operazioni di ottimizzazione volte ad alleggerire e migliorare i processi che vi sono alla base.

Come Funzionano i Giochi

Ogni videogioco è sostanzialmente una rappresentazione di un mondo virtuale simulato sulla base di un circuito composto da tre fasi: input esterni, aggiornamento dello stato del mondo e renderizzazione della scena.
Un input esterno è costituito da qualsiasi informazione provenga dall’esterno del mondo virtuale. Esso può essere un comando inviato dal giocatore tramite una periferica, oppure, nel caso dei giochi multiplayer, un’informazione proveniente dalla rete.
Durante l’aggiornamento dello stato del mondo, il motore elabora le informazioni ricevute dagli input esterni e, sulla base di quelle preesistenti, apporta dei cambiamenti al mondo di gioco. Lo stato del mondo è descritto da una moltitudine di elementi, come gli oggetti in esso presenti, le loro caratteristiche, le azioni in corso e via dicendo. La ripetizione di questi due passaggi permette l’evoluzione nel tempo dello stato del mondo.
L’ultimo passaggio è quello di renderizzazione. In questa fase, il motore riproduce su schermo tutti gli oggetti visibili al giocatore, nelle condizioni e con le caratteristiche elaborate durante l’aggiornamento. Così facendo, l’utente può vedere cosa sta accadendo nel mondo di gioco e reagire di conseguenza.

Prestazioni_Ottimizzazioni - ottimizzazioni_1.jpg

Gli ultimi due step, aggiornamento e renderizzazione, richiedono l’esecuzione di una serie di calcoli matematici di complessità variabile. Il tempo necessario al loro completamento determinerà il numero di volte che sarà possibile ripetere l’intero circuito in un secondo. Ovvero il numero di frame che una macchina potrà riprodurre per secondo: gli fps.
Se l’elaborazione dell’intero processo richiederà 16 millisecondi, allora in un secondo verranno calcolati e renderizzati 60 frame, ovvero si avrà un framerate di 60 fps. Se invece questo processo richiederà 50 millisecondi, il valore degli fps scenderà a 20.
In questo senso, lo scopo delle ottimizzazioni consiste nel ridurre la quantità di calcoli da effettuare ad ogni passaggio, così da minimizzare il tempo necessario a ripetere il circuito ed aumentare la quantità di frame riprodotti per secondo.

La Componente Hardware

Il meccanismo sopra riportato non è altro che un’estrema semplificazione del sistema di funzionamento dei videogiochi. Tra le altre cose, esso non tiene conto della maniera con cui lavorano i computer moderni.
Ogni PC contiene genericamente due unità di elaborazione dati: il processore, o CPU, e la scheda grafica, o GPU. Nei giochi, la CPU viene utilizzata per l’esecuzione dei calcoli relativi all’aggiornamento dello stato del mondo, mentre la GPU effettua la renderizzazione. Le due entità lavorano in parallelo: mentre la scheda grafica renderizza un frame, la CPU solitamente elabora quelli successivi. Questi vengono caricati e mantenuti in memoria per permettere alla GPU di riprodurli non appena sarà terminata la renderizzazione del frame precedente.

Prestazioni_Ottimizzazioni - ottimizzazioni_3.jpg

Tuttavia, il numero di frame che è possibile salvare in memoria è limitata, perché non esistono computer dotati di memoria infinita. Se la GPU non riuscirà a mantenere il passo della CPU, il processore ad un certo punto dovrà fermare l’elaborazione dei frame successivi ed attendere che la scheda grafica si metta in pari. Ciò causerà un ritardo nella riproduzione su schermo degli aggiornamenti di gioco, il quale andrà ad inficiare sull’esperienza utente.
Si può però verificare anche il caso opposto. Questa evenienza si presenta quando la CPU non riesce ad elaborare nuovi frame con una velocità maggiore o uguale di quella con cui la GPU li renderizza. Tale stato viene definito starvation.

Prestazioni_Ottimizzazioni - ottimizzazioni_5.jpg

Dal momento che in ogni computer ci sarà sempre un componente meno performante dell’altro, che si tratti della scheda video o del processore, individuare quali di essi costituisca il collo di bottiglia è di cruciale importanza. Ad esempio, ottimizzare una GPU che è già in condizioni di starvation non porterebbe ad alcun miglioramento degli fps.
Il metodo con cui tale collo di bottiglia viene individuato è definito Analisi del Percorso Critico [NdR: Critical Path Analysis in Inglese].

Il Load Balancing

Un’ulteriore complicazione di questa scenario è costituita dal fatto che ogni CPU è in grado di ripartire i processi in più parti ed eseguirle parallelamente, così da velocizzare l’elaborazione dati. Questo approccio viene definito threading e risente di problemi di gestione del carico di lavoro simili a quelli da cui è affetto il binomio CPU/GPU.

Quando un processo viene suddiviso in più thread, è importante che ciascuna di queste operazioni venga elaborata all’incirca nello stesso periodo di tempo. Di conseguenza, solitamente i calcoli vengono divisi in maniera tale che ogni thread abbia grosso modo lo stesso tempo di elaborazione. Questo metodo di distribuzione prende il nome di load balancing [NdT: letteralmente Bilanciamento del Carico] e permette di evitare che un thread ancora in esecuzione blocchi gli altri.

Prestazioni_Ottimizzazioni - ottimizzazioni_6.jpg

In teoria, un corretto load balancing richiede di stimare i tempi di elaborazione di ogni singola parte di un aggiornamento del mondo di gioco, per poi ripartirli in operazioni di carico simile. Ciò è tanto più complesso, quanto maggiore è il numero di calcoli presenti ed il numero di entità a cui essi sono riferiti. Inoltre, il load balancing risente anche delle specifiche del computer in uso, come ad esempio il numero di core. Di conseguenza, nella pratica è quasi impossibile ripartire i vari aggiornamenti di gioco in thread di durata simile, soprattutto in un progetto complesso come Star Citizen.

Per sopperire a questi problemi, si è scelto di dividere gli aggiornamenti in batch, o gruppi.
Un batch consiste di un insieme di processi relativi ad uno stesso componente, entità o oggetto di gioco. Ad esempio, tutti gli aggiornamenti riguardanti un determinato personaggio costituiscono un unico batch. Per cui quelli relativi a due o più avatar possono essere demandati a due o più core differenti, così da utilizzare in maniera più efficiente le risorse a disposizione. Attualmente è in corso la conversione di tutti i sistemi di gioco a questo approccio di esecuzione, che permetterà di migliorare le prestazioni in game.

La Latenza di Input

Il framerate tuttavia non è importante soltanto per la qualità visiva del gioco. I valori di fps influenzano notevolmente anche il tempo di elaborazione degli input del giocatore, nel senso che più bassi sono gli fps, maggiore è il tempo che passerà tra l’invio di un comando e la visualizzazione del suo effetto. Ciò causa l’introduzione di una latenza che può inficiare notevolmente sull’esperienza di gioco.

Prestazioni_Ottimizzazioni - ottimizzazioni_7.jpg

Questo avviene perché l’elaborazione degli input e delle loro conseguenze rientra nella fase di aggiornamento dello stato del mondo, ma per produrre un risultato visibile è necessario che vengano elaborati più frame.
Se il loop di aggiornamento e rendering impiegasse 16 millisecondi, ma per vedere l’effetto dell’input fosse necessario attendere 3 aggiornamenti, quindi 3 frame, il tempo totale necessario sarebbe di 48 millisecondi. Se invece l’elaborazione di un frame richiedesse 50 millisecondi, il tempo che dovrebbe passare prima di poter vedere gli effetti dell’input sarebbe di 150 millisecondi. Questa differenza verrebbe percepita dall’utente come una latenza nella ricezione dei suoi comandi.

La Questione Server

I server di Star Citizen lavorano a 30 fps, il che vuol dire che effettuano 30 aggiornamenti del mondo di gioco per secondo. I client di gioco, invece, hanno un valore di fps bersaglio pari a 60. Ciò avviene in quanto server e client non lavorano in lockstep, ovvero non c’è una corrispondenza precisa tra la ricezione delle informazioni del server e l’elaborazione di quelle locali.

Quando si è in regime di lockstep, il client solitamente attende dal server i dati relativi ad ogni fase di elaborazione. Questi vengono trattati alla stregua di input esterni e permettono di mantenere un’esperienza di gioco più o meno identica su tutti i client, in termini di avvenimenti in gioco. Tuttavia, tale tecnica presenta dei grossi limiti. Essa richiede che il client attenda la ricezione delle informazioni dal server e che l’intera mole di dati venga correttamente trasmessa e ricevuta ad ogni frame.

Dal momento che la latenza della connessione internet non è uguale per tutti, macchine con latenze differenti impiegherebbero tempi diversi ad elaborare le stesse informazioni. Conseguentemente, alcuni giocatori potrebbero riscontrare un ritardo nella visualizzazione dell’azione di gioco, fenomeno noto come desync. Ciò si può verificare anche quando l’informazione semplicemente non viene recepita in maniera corretta, come in caso di perdita di pacchetti dati.

L’altro problema correlato a questo approccio è rappresentato dalla mole di dati da trasmettere.
Maggiore è la loro quantità, più è probabile che si verifichino problemi in fase di trasmissione e ricezione. Per questo motivo, solitamente si cerca di limitare il più possibile le dimensioni di queste informazioni, o pacchetti, così da evitare di incappare in situazioni del genere. L’implicazione diretta di questo fatto è che il sistema del lockstep non è applicabile nei casi bisogna trasmettere ingenti quantitativi di dati. È questo il caso di Star Citizen.

Pertanto, per il progetto si è scelto di perseguire un’altra strada, ovvero di fare in modo che ogni client riceva un aggiornamento ogni 33 millisecondi, invece che ogni 16.
Dal momento che in un regime a 60fps ciò equivale a ricevere i dati una volta ogni due frame, per sopperire a questa mancanza i client devono elaborare da sé le informazioni riguardanti il frame di intermezzo. Al frame successivo, tuttavia, il client paragona i dati in suo possesso con quelli ricevuti dal client server effettua le dovute correzioni. In questo modo è possibile limitare la quantità di dati inviati, riproducendo al contempo la stessa esperienza di gioco per tutti.

Esempi di Ottimizzazione

Le ottimizzazioni solitamente comportano una riduzione della quantità di operazioni da effettuare per un determinato aggiornamento, o una parte di esso.
Nel caso di Star Citizen, una prima ottimizzazione consisterebbe nel diminuire la quantità di entità di cui ogni client deve tenere traccia. Minore sarà il numero degli elementi da aggiornare, minore sarà anche la quantità di calcoli da effettuare ad ogni frame. Per non influire negativamente sull’esperienza di gioco, però, è necessario eliminare esclusivamente quegli elementi che non rientrano nella sfera di azione del giocatore. A questo scopo, è possibile basarsi su un dato come la distanza esistente tra due entità, per poi rimuovere gli aggiornamenti da tutti quegli oggetti che si trovano oltre un valore predefinito. Questa strategia è definita bind culling e ne parleremo nel dettaglio più avanti.

Prestazioni_Ottimizzazioni - ottimizzazioni_8.jpg

L’atto stesso di rimuovere la lista di elementi da aggiornare, però, richiede di effettuare una serie di operazioni.
Se si ha una lista di 1000 entità, l’eliminazione di una di esse richiede di riscrivere la lista stessa, così da evitare che al suo interno si formino degli spazi vuoti. Esistono svariati approcci con cui è possibile fare ciò, il più semplice dei quali comporta di traslare il posto di tutti gli altri elementi della lista di un’unità. Questo metodo però richiede di effettuare n operazioni, dove n è pari al numero di oggetti da spostare.
Un’altra strategia, meno computazionalmente esosa, prevede invece di conservare all’interno degli oggetti stessi della lista l’informazione relativa al posto da loro occupato al suo interno. Così facendo, quando un’entità verrà rimossa si potrà semplicemente cancellare il riferimento alla sua posizione, per poi assegnarlo ad un elemento posizionato all’estremità della lista. Ciò permetterà di svolgere soltanto 2 operazioni, invece che n.

Prestazioni_Ottimizzazioni - ottimizzazioni_9.jpg

Questi esempi rappresentano il genere di lavoro che viene solitamente effettuato durante i passaggi di ottimizzazione. Per far questo è però prima necessario analizzare il codice per individuare le porzioni che rallentano l’elaborazione dei frame, che si tratti della fase di aggiornamento del mondo (lato CPU) o quella di renderizzazione (lato GPU).

GPU e Navi

A livello di renderizzazione, le ottimizzazioni attualmente in corso consistono nel ridurre il più possibile il numero di draw call con cui vengono descritti gli oggetti del gioco, soprattutto le navi.
Una draw call non è altro che un blocco di informazioni contenente i dati riguardanti un elemento, che si tratti di texture, shader, geometria e via dicendo. Maggiore è il loro numero, più fatica farà la GPU a renderizzare la scena, semplicemente perché ci saranno più cose da rappresentare.

Nel caso di Star Citizen, si è scelto di lavorare con un limite massimo assoluto di 2500 draw call. Questo vuol dire che in ogni momento, la GPU non dovrà effettuare più di 2500 draw call.
La renderizzazione del modello a qualità e definizione massima di una nave solitamente richiede dalle 500 alle 800 draw call. Per ridurre questi valori, gli artisti ed i programmatori tecnici hanno sviluppato il sistema dei Livelli di Dettaglio, o LOD. Essi consistono di una serie di versioni di qualità inferiore dello stesso oggetto, che vengono riprodotte in funzione della distanza a cui quell’elemento viene visualizzato. Più lontano esso sarà, minore sarà la qualità del suo modello e quindi il numero di draw call ad esso associate.
Un altro metodo per ridurre questi numeri è la revisione degli stati di danneggiamento dei vascelli.
In passato, la distruzione di un velivolo portava alla creazione di svariati detriti, ciascuno dei quali veniva realizzato a mano da un artista. Attualmente, tali oggetti vengono ottenuti semplicemente spaccando ed applicando shader differenti allo scafo della nave, per cui il numero di draw call risultante si è notevolmente ridotto.
Alternativamente, è possibile combinare più elementi in un unico oggetto di renderizzazione, diminuendo così la quantità di draw call ad esso associate. Questa tecnica viene definita skinning.

Oltre a ridurre la qualità o il numero di istruzioni di renderizzazione associate ad un’entità, è possibile migliorare le prestazioni anche renderizzando soltanto una parte di un velivolo.
Ad esempio, se un giocatore sta guardando una nave dall’esterno, non avrà senso far elaborare alla scheda video anche i dati riguardanti i suoi interni. Per ottenere questo risultato si usa una tecnica chiamata portal culling, che consiste nel dividere una scena in più finestre, o parti, per poi renderizzarle singolarmente a seconda delle necessità.
In questo caso, un vascello può essere diviso nel suo scafo esterno e nelle aree interne. Se si è dentro di esso, si potrà renderizzare soltanto gli interni visibili e non l’esterno, o viceversa. Ma i due saranno collegati da un ‘portale’, quale la rampa di accesso alla nave. Aprendo quest’ultima, si potrà dire alla GPU di rappresentare anche lo scafo esterno del velivolo, così da mostrarlo al giocatore. Al momento sono in corso alcuni lavori di bugfix di questo sistema, dato che sono stati riscontrati dei bug con alcune navi, come la Caterpillar.

Prestazioni_Ottimizzazioni - ottimizzazioni_10.jpg

Infine, è in fase di sviluppo una tecnologia chiamata signed distance field.
Si tratta di un approccio con cui è possibile descrivere un volume basandosi sulle distanze esistenti tra gli elementi che lo costituiscono. Rispetto ai voxel, che invece sono una rappresentazione volumetrica dei pixel, questa tecnica ha il vantaggio di essere molto meno pesante e più flessibile. Essa permetterà di descrivere meglio le forme delle navi e degli scudi, che riprodurranno meglio la loro silhoutte.

Il Netcode

In passato, il netcode era stato la fonte di svariati problemi per Star Citizen.
La ragione consisteva nel fatto che, in un’istanza da 24 giocatori, il server doveva ricalcolare le stesse informazioni 24 volte, una per utente, per poi inviarle su 24 canali differenti. Dal momento che queste operazioni non erano parallelizzate, esse venivano demandate tutte allo stesso thread, per cui si verificava un rallentamento nella loro esecuzione. Questo a sua volta bloccava i processi attivi sul thread principale, che prima di poter iniziare a lavorare sul frame successivo doveva aspettare che il netcode inviasse tutti i dati. Ciò determinava i crolli di fps ed i comportamenti anomali riscontrati pre 3.0.

Prestazioni_Ottimizzazioni - ottimizzazioni_11.jpg

Con questo aggiornamento, invece, è stata sostanzialmente modifica la logica di lavoro del netcode.
Innanzitutto, con la parziale implementazione delle variabili serializzate è stato possibile spezzare gli aggiornamenti in più parti, ciascuna demandabile a più thread che lavorano in parallelo. Per cui quando il server deve inviare le informazioni ai client tramite la rete, queste vengono impacchettate e spedite in minor tempo, evitando il blocco che si verificava in precedenza. L’adozione della tecnica dei metodi remoti, infine, ha permesso di mantenere un controllo condiviso su tutte le variabili ed i dati di aggiornamento, nonostante il loro spezzettamento.

Prestazioni_Ottimizzazioni - ottimizzazioni_12.jpg

Dal punto di vista dei client, invece, il netcode non è mai stato davvero un problema.
Tutto quello che un client deve fare è ricevere l’informazione dal server, aprirla ed elaborarla. Questo processo è molto più veloce di quello di preparazione ed invio dei dati da parte del server stesso. Inoltre, la quantità di informazioni spedite dal client al server è di gran lunga inferiore alla controparte server. Per cui anche in questo caso i tempi di elaborazione sono ridotti.

Il Bind Culling

Il vero problema dei client consiste nell’elaborazione locale dei dati di simulazione, ovvero quelli di aggiornamento dello stato del mondo.
Ciò è dovuto alla differenza nella potenza di calcolo tra server e client, che su questi ultimi causa dei rallentamenti con conseguente riduzione degli fps. Per ovviare a questo problema, è in via di implementazione la tecnologia del bind culling.

Il bind culling permette di rimuovere alcune entità, nonché i calcoli ad essi correlati, dagli aggiornamenti che i client devono elaborare ad ogni frame. Questa rimozione viene effettuata tenendo conto della posizione in cui si trova il giocatore e della sua distanza dalle altre entità. Se ad esempio un utente si trova su Port Olisar, sapere che un personaggio su Levsky sta uscendo da un avamposto gli sarà completamente inutile.
Questa tecnica ha il vantaggio aggiuntivo di ridurre leggermente anche il carico del server, in quanto potrà limitare il numero di informazioni da inviare ai vari client.

Tuttavia, proprio questo meccanismo di funzionamento rende il bind culling una tecnologia complicata e non di facile implementazione. Perché sia possibile circoscrivere i dati da inviare ai client, il server deve essere in grado di distinguere tra quelli utili e quelli inutili per ogni giocatore. Quelli utili andranno comunicati, mentre gli altri no.
La logica attuale del netcode è basata su assunzioni totalmente opposte. Al momento essa prevede di aggiornare costantemente tutti i client con le informazioni relative a tutte le entità dell’istanza. Pertanto, bisognerà cambiare buona parte delle funzioni del netcode, per poi testarle.

Un problema ulteriore è dato dal fatto che bisognerà anche regolare lo spawn, o comparsa delle entità in maniera completamente differente.
Per adesso Star Citizen sfrutta un meccanismo di spawn sincrono, per cui quando il giocatore entra in un’istanza, il client crea tutte le entità in essa presenti. Con il bind culling ciò non sarà più necessario, perché andranno generate soltanto le entità situate vicino all’utente.  Quando però questo si sposterà, il server dovrà comunicare al client le informazioni relative agli elementi presenti nella nuova zona, che quindi il client stesso dovrà far spawnare, mentre quelli vecchi andranno eliminati.
Ciò richiede di adottare un meccanismo di spawn asincrono, che non è altro che il sistema di Streaming dei Contenitori Oggetto.

Il sistema di Streaming dei Contenitori Oggetto permetterà di caricare e scaricare dinamicamente tutte le informazioni e le entità necessarie al client.
Nel momento in cui un giocatore cambierà zona, il server informerà il client che dovrà iniziare a caricare i dati presenti in quell’area, i quali saranno già stati divisi per gruppi, o contenitori. Questa struttura gerarchica faciliterà l’accesso alle informazioni e la gestione dei loro processi di caricamento ed eliminazione. Essi verranno lanciati in parallelo al thread principale ed effettueranno tutte le operazioni del caso, come l’associazione delle entità alla griglia fisica, il collegamento alla Sussistenza e via dicendo. Perché questo meccanismo possa funzionare correttamente, tali operazioni andranno completate prima che il giocatore arrivi sul luogo.

Il fatto che il client non abbia sempre in memoria i dati riguardanti ogni oggetto dell’istanza potrebbe però creare dei problemi. Un esempio è dato dall’eventualità in cui una missione richieda di mostrare la posizione di un’entità che posizionata su un altro pianeta. Dal momento che essa non è stata caricata, in quanto troppo lontana, il client non avrebbe modo di visualizzare questa informazione. Parte dei lavori attualmente in corso sono incentrati proprio sulla risoluzione di queste criticità.

Per tutti questi motivi, il rilascio del bind culling è stato posticipato ad uno degli aggiornamenti successivi alla 3.1. Al suo posto, però, verrà implementato il bind culling delle variabili serializzate.
Similmente al bind culling, questa tecnologia permetterà di ridurre l’entità dei dati che i client dovranno elaborare, disattivando gli aggiornamenti riguardanti gli oggetti troppo lontani dal giocatore. Le loro informazioni saranno ancora presenti in memoria, ma dal momento che non verranno aggiornate, ciò dovrebbe portare ad un incremento delle prestazioni simile a quello riscontrabile con il bind culling.

Quando Ottimizzare

Dal momento che realizzare ed implementare delle ottimizzazioni è un lavoro arduo e complesso, non è sempre possibile ottimizzare tutti i sistemi di gioco. Soprattutto quando essi sono ancora in sviluppo.
In linea di massima, l’ottimizzazione è un’attività che viene effettuata dopo aver realizzato tutte le funzioni, il codice e le tecnologie previste. Applicare delle ottimizzazioni durante la fase di sviluppo di un titolo comporta di togliere tempo e risorse all’attività di produzione, con conseguenti allungamento delle tempistiche di lavoro. In aggiunta, i cambiamenti apportati al codice lo rendono spesso più complicato e quindi più prono ai bug, senza considerare che essi vanno anche testati volta per volta. Infine, può capitare che dei problemi inaspettati costringano a rivedere o cambiare integralmente alcuni componenti, vanificando le ottimizzazioni apportate.

Per questi motivi, trovare il giusto compromesso tra sviluppo ed ottimizzazione è un fatto essenziale. Ma dal momento che i fan del progetto partecipano in prima persona a tutti i test, è anche importante assicurarsi che le build funzionino decentemente e che la conta degli fps non sia troppo bassa. A questo scopo, le nuove versioni del gioco vengono sottoposte a frequenti analisi prestazionali.

Prestazioni_Ottimizzazioni - ottimizzazioni_13.jpg

Queste permettono di individuare i componenti troppo pesanti e/o che rallentano eccessivamente l’esecuzione dei processi.
L’analisi viene effettuata sfruttando svariati strumenti. Il primo è il sampling profiler, che permette di registrare i processi in atto sulla CPU in un dato momento. Il suo scopo consiste nel raccogliere una statistica della frequenza con cui vengono lanciati determinati processi. Solitamente, una frequenza di riscontro elevata è associata ad un alto costo di esecuzione, per cui la funzione in esame potrebbe dover essere ottimizzata.
L’assembling profiler, invece, fornisce dati relativi al tempo di esecuzione di ogni singola operazione. Infine, per avere maggiori informazioni sui processi lanciati dalla CPU in situazioni specifiche, nonché la ripartizione dei thread, si ricorre all’instrumented profiler.

Benché questi strumenti permettano di farsi un’idea completa delle ottimizzazioni da apportare, non è sempre possibile elaborarle per tempo.
A volte non si hanno risorse sufficienti a svilupparle. Oppure il componente in esame è così complesso, che il suo miglioramento richiede di risolvere svariate dipendenze e quindi di coinvolgere più programmatori. In alcuni casi le modifiche da apportare sono particolarmente delicate, per cui i tempi richiesti per la loro realizzazione sono lunghi. Tutto ciò può determinare dei ritardi che, in ultima analisi, possono decretare il posticipo di alcune ottimizzazioni alle build successive.

Bug e Telemetria

Di recente, è stato sviluppato un nuovo sistema di telemetria che permette di tenere traccia dei problemi delle varie build di gioco, nonché delle prestazioni riscontrate con esse.
Queste informazioni rivestono una grande importanza, in quanto permettono di correlare le modifiche apportate tra le varie versioni di Star Citizen con parametri come gli fps. In questo modo è possibile verificare se le ottimizzazioni implementate stanno avendo o meno gli effetti sperati, per poi pianificare di conseguenza i lavori successivi.

In aggiunta, la nuova telemetria è in grado di individuare e segnalare automaticamente i repentini crolli nelle prestazioni, inviando tutti i dati ad essi relativi. Questa funzionalità di auto-cattura è ancora in fase di sviluppo preliminare, ma aiuterà i programmatori a capire quali eventi saranno responsabili della riduzione degli fps, assieme alle loro possibili cause.

Prestazioni_Ottimizzazioni - ottimizzazioni_14.jpg

Infine, è in fase di preparazione una macchina di auto test, il cui scopo sarà di provare automaticamente le nuove build di gioco e raccogliere i dati ad esse relative.
Questo sistema lavorerà con dei client headless che simuleranno la presenza e le attività dei giocatori secondo schemi di comportamento predefiniti. Ad esempio, potrebbero simulare lo spawn di decine di personaggi o navi in uno stesso punto dell’universo, ciascuna delle quali eseguirà delle attività differenti. Con l’aumento delle dimensioni delle istanze, questi client headless rivestiranno un’importanza sempre maggiore.
Già con i server da 50 giocatori è difficile organizzare dei playtest interni che permettano di riempire tutti gli slot a disposizione. In aggiunta, la raccolta dati è altrettanto complicata, dato che ogni partecipante potrebbe riferire cose differenti o dimenticare di comunicare qualche dato. Per cui la capacità di effettuare dei test automatici con un sistema di auto-campionamento dei dati sarà estremamente preziosa. Essi permetteranno di individuare eventuali problemi presenti nelle nuove build, prima che queste vengano inviate agli ambienti Live e PTU.

Tutte queste informazioni verranno affiancate a quelle più specifiche ricavate direttamente dai team di QA e dai playtest interni, per meglio determinare le criticità del gioco e le loro possibili soluzioni o miglioramenti.

Le Implicazioni dell’Early Access

Solitamente, per la maggior parte del ciclo di un sviluppo di un gioco gli fps in game non superano le 15 unità. Questo perché in quel frangente lo scopo è, per l’appunto, la creazione di tutto il codice, i componenti, gli oggetti e le funzionalità necessarie. L’ottimizzazione avviene alla fine, quando i sistemi sono stati consolidati e si conosce bene il meccanismo di funzionamento di ciascuno di essi.

Tuttavia Star Citizen è un titolo in early access, il che vuol dire che gli utenti devono avere la possibilità di provarlo con prestazioni decenti. Per cui parte dell’attività di sviluppo viene dedicata ad ottimizzare cose ancora da rifinire o modificare, allungando così inevitabilmente anche le tempistiche lavorative.

Ma proprio perché il focus primario è lo sviluppo del titolo, bisogna anche trovare un compromesso tra produzione e prestazioni. Questo vuol dire che con il tempo verranno introdotte sempre nuove ottimizzazioni, le quali però riguarderanno esclusivamente i componenti più pesanti. Non saranno grandi ottimizzazioni sistemiche a 360°.
Ciò nonostante, in alcune build si potrà comunque riscontrare un peggioramento delle prestazioni. Ogni volta che verrà introdotto un nuovo sistema o funzionalità, questo potrebbe generare dei problemi, i quali verranno risolti nelle patch successive.

Per questi motivi, durante lo sviluppo di Star Citizen non sarà mai possibile arrivare ai valori di fps riscontrabili nei giochi finiti. Proprio perché lo scopo, al momento, non è questo.

 

Articolo originale disponibile presso le Roberts Space Industries.