Condividi tramite


Case study - Creazione di una galassia in realtà mista

Prima di Microsoft HoloLens spedito, abbiamo chiesto alla community per sviluppatori quale tipo di app vogliono vedere una compilazione del team interno esperto per il nuovo dispositivo. Più di 5000 idee sono state condivise, e dopo un sondaggio twitter di 24 ore, il vincitore era un'idea denominata Galaxy Explorer.

Andy Zibits, il capo dell'arte nel progetto e Karim Luccin, il tecnico grafico del team, parla del lavoro collaborativo tra arte e ingegneria che ha portato alla creazione di una rappresentazione accurata e interattiva della galassia Milky Way in Galaxy Explorer.

La tecnologia

Il nostro team , costituito da due designer, tre sviluppatori, quattro artisti, un produttore e un tester, hanno avuto sei settimane per creare un'app completamente funzionale che consente alle persone di imparare e esplorare la vastità e la bellezza del nostro Milky Way Galaxy.

Volevamo sfruttare al meglio la capacità di HoloLens di eseguire il rendering di oggetti 3D direttamente nello spazio vivente, quindi abbiamo deciso di creare una galassia realistica in cui le persone sarebbero in grado di ingrandire vicino e vedere singole stelle, ognuna delle proprie traiettorie.

Nella prima settimana di sviluppo, abbiamo ottenuto alcuni obiettivi per la nostra rappresentazione della Galassia Milky Way: è necessario avere profondità, movimento e sentirsi volumetrico- pieno di stelle che aiutano a creare la forma della galassia.

Il problema con la creazione di una galassia animata che aveva miliardi di stelle era che il numero di singoli elementi che richiedono l'aggiornamento sarebbe troppo grande per fotogramma per HoloLens per animare usando la CPU. La nostra soluzione ha coinvolto una complessa combinazione di arte e scienza.

Dietro le quinte

Per consentire alle persone di esplorare le singole stelle, il primo passaggio era quello di capire quanti particelle potremmo eseguire contemporaneamente.

Particelle di rendering

Le CPU correnti sono ideali per l'elaborazione di attività seriali e fino a alcune attività parallele contemporaneamente (a seconda del numero di core che hanno), ma le GPU sono molto più efficaci per l'elaborazione di migliaia di operazioni in parallelo. Tuttavia, poiché in genere non condividono la stessa memoria della CPU, lo scambio di dati tra GPU CPU<>può diventare rapidamente un collo di bottiglia. La nostra soluzione era quella di creare una galassia sulla GPU e doveva vivere completamente sulla GPU.

Abbiamo iniziato i test di stress con migliaia di particelle di punto in vari modelli. Ciò ci ha consentito di ottenere la galassia su HoloLens per vedere cosa ha funzionato e cosa non ha fatto.

Creazione della posizione delle stelle

Uno dei membri del team aveva già scritto il codice C# che generava stelle alla loro posizione iniziale. Le stelle si trovano su un puntoni di sospensione e la loro posizione può essere descritta da (curveOffset, ellipseSize, elevazione) dove curveOffset è l'angolo della star lungo i puntini di sospensione, ellipseSize è la dimensione dell'ellisse lungo X e Z e elevazione dell'elevazione corretta della star all'interno della galassia. È quindi possibile creare un buffer (ComputeBuffer di Unity) inizializzato con ogni attributo star e inviarlo nella GPU in cui sarebbe attivo per il resto dell'esperienza. Per disegnare questo buffer, usiamo DrawProcedural di Unity che consente di eseguire uno shader (codice in una GPU) in un set arbitrario di punti senza avere una mesh effettiva che rappresenta la galassia:

CPU:

GraphicsDrawProcedural(MeshTopology.Points, starCount, 1);

GPU:

v2g vert (uint index : SV_VertexID)
{

 // _Stars is the buffer we created that contains the initial state of the system
 StarDescriptor star = _Stars[index];
 …

}

Abbiamo iniziato con modelli circolari non elaborati con migliaia di particelle. Questo ci ha dato la prova che abbiamo dovuto gestire molte particelle E eseguirlo a velocità elevate, ma non siamo stati soddisfatti della forma complessiva della galassia. Per migliorare la forma, abbiamo tentato vari modelli e sistemi di particella con rotazione. Questi erano inizialmente promettenti perché il numero di particelle e prestazioni rimanevano coerenti, ma la forma si è interrotta vicino al centro e le stelle emettevano verso l'esterno che non era realistico. Abbiamo bisogno di un'emissione che ci permetterebbe di manipolare il tempo e di spostare le particelle in modo realistico, ciclo sempre più vicino al centro della galassia.

Abbiamo tentato vari modelli e sistemi di particella che ruotavano, come questi.

Abbiamo tentato vari modelli e sistemi di particella che ruotavano, come questi.

Il nostro team ha fatto una ricerca sul modo in cui le galassie funzionano e abbiamo fatto un sistema di particella personalizzato in modo specifico per la galassia in modo che potremmo spostare le particelle sui puntini di sospensione in base alla "teoria dell'onda densità", che teorizza che le braccia di una galassia sono aree di densità più elevata, ma in flusso costante, come un traffico ingorgo. Sembra stabile e solido, ma le stelle si stanno effettivamente spostando e fuori dalle braccia mentre si spostano lungo i rispettivi puntini di sospensione. Nel nostro sistema le particelle non esistono mai sulla CPU, generano le schede e le indirizzano tutte sulla GPU, quindi l'intero sistema è semplicemente lo stato iniziale + ora. È stato avanzamento come segue:

Progressione del sistema di particelle con rendering GPU

Progressione del sistema di particelle con rendering GPU

Una volta aggiunti i puntini di sospensione sufficienti e vengono impostati per ruotare, le galassie iniziarono a formare "braccia" dove il movimento delle stelle converge. La spaziatura delle stelle lungo ogni percorso ellittico è stata data una certa casualità e ogni star ha aggiunto un po' di casualità posizionale. In questo modo è stata creata una distribuzione più naturale del movimento star e della forma del braccio. Infine, è stata aggiunta la possibilità di guidare il colore in base alla distanza dal centro.

Creazione del movimento delle stelle

Per animare il movimento generale star, è necessario aggiungere un angolo costante per ogni fotogramma e ottenere stelle che si spostano lungo i puntini di sospensione a una velocità radiale costante. Questo è il motivo principale per l'uso di curveOffset. Questo non è tecnicamente corretto perché le stelle si spostano più velocemente lungo i lati lunghi dei puntini di sospensione, ma il movimento generale si sentiva buono.

Le stelle si spostano più velocemente sull'arco lungo, più lento sui bordi.

Le stelle si spostano più velocemente sull'arco lungo, più lento sui bordi.

Con questo, ogni star è completamente descritto da (curveOffset, puntini di sospensione, elevazione, Età) dove Age è un accumulo del tempo totale passato dopo il caricamento della scena.

float3 ComputeStarPosition(StarDescriptor star)
{

  float curveOffset = star.curveOffset + Age;
  
  // this will be coded as a “sincos” on the hardware which will compute both sides
  float x = cos(curveOffset) * star.xRadii;
  float z = sin(curveOffset) * star.zRadii;
   
  return float3(x, star.elevation, z);
  
}

Ciò ci ha consentito di generare decine di migliaia di stelle una volta all'inizio dell'applicazione, quindi abbiamo animato un singolo set di stelle lungo le curve stabilite. Poiché tutto si trova nella GPU, il sistema può animare tutte le stelle in parallelo senza costi per la CPU.

Ecco cosa sembra quando si disegna quad bianchi.

Ecco cosa sembra quando si disegna quad bianchi.

Per rendere ogni faccia quad la fotocamera, abbiamo usato un shader geometry per trasformare ogni star posizione in un rettangolo 2D sullo schermo che conterrà la trama star.

Diamanti anziché quad.

Diamanti anziché quad.

Poiché volevamo limitare l'overdraw (numero di volte in cui un pixel verrà elaborato) il più possibile, abbiamo ruotato i nostri quad in modo che abbiano meno sovrapposizioni.

Aggiunta di cloud

Esistono molti modi per ottenere una sensazione volumetrica con particelle, dal raggio in marcia all'interno di un volume per disegnare il maggior numero possibile di particelle per simulare un cloud. Il raggio in tempo reale stava per essere troppo costoso e difficile da creare, quindi abbiamo provato a creare un sistema imposter usando un metodo per il rendering delle foreste nei giochi, con molte immagini 2D di alberi che si affacciano sulla fotocamera. Quando si esegue questa operazione in un gioco, è possibile avere trame di alberi sottoposti a rendering da una fotocamera che ruota intorno, salvare tutte le immagini e in fase di esecuzione per ogni scheda di cartellone, selezionare l'immagine corrispondente alla direzione della visualizzazione. Questo non funziona anche quando le immagini sono ologrammi. La differenza tra l'occhio sinistro e l'occhio destro lo rendono in modo che abbiamo bisogno di una risoluzione molto più alta, altrimenti sembra semplicemente piatta, alias o ripetitiva.

Nel secondo tentativo abbiamo cercato di avere il maggior numero possibile di particelle. I migliori oggetti visivi sono stati ottenuti quando abbiamo disegnato particelle e sfocate in modo aggiuntivo prima di aggiungerli alla scena. I problemi tipici di tale approccio sono stati correlati al numero di particelle che potremmo disegnare in un'unica volta e la quantità di area dello schermo coperta mentre mantengono ancora 60fps. La sfocatura dell'immagine risultante per ottenere questa sensazione cloud è in genere un'operazione molto costosa.

Senza trama, questo è ciò che le nuvole sembrano con opacità 2%.

Senza trama, questo è ciò che le nuvole sembrano con opacità 2%.

Essere additivi e avere molti di loro significa che avremmo diversi quad sopra l'uno dell'altro, ripetutamente ombreggiatura lo stesso pixel. Al centro della galassia, lo stesso pixel ha centinaia di quad sopra l'uno all'altro e questo ha un costo enorme quando viene fatto schermo intero.

Facendo cloud a schermo intero e cercando di sfuocarli sarebbe stata una cattiva idea, quindi abbiamo deciso di lasciare che l'hardware faccia il lavoro per noi.

Un po' di contesto prima

Quando si usano trame in un gioco le dimensioni della trama raramente corrispondono all'area in cui si vuole usarla, ma è possibile usare un tipo di filtro di trama diverso per ottenere la scheda grafica per interpolare il colore desiderato dai pixel della trama (Filtro trama). Il filtro che interessa è il filtro bilineare che calcola il valore di qualsiasi pixel usando i 4 vicini più vicini.

Originale prima del filtro

Risultato dopo il filtro

Usando questa proprietà, si noterà che ogni volta che si tenta di disegnare una trama in un'area due volte più grande, si offusca il risultato.

Invece di eseguire il rendering in uno schermo intero e perdere quei millisecondi preziosi che potremmo spendere su un altro, viene eseguito il rendering in una versione minuscola dello schermo. Copiando quindi questa trama e estendendola per un fattore di 2 volte, torniamo a schermo intero durante il sfocatura del contenuto nel processo.

x3 torna alla risoluzione completa.

x3 torna alla risoluzione completa.

Ciò ci ha consentito di ottenere la parte cloud con solo una frazione del costo originale. Invece di aggiungere cloud sulla risoluzione completa, dipingiamo solo 1/64° dei pixel e si estende solo la trama alla risoluzione completa.

Sinistra, con un lusso da 1/8 a piena risoluzione; e giusto, con 3 lusso con potenza 2.

Sinistra, con un lusso da 1/8 a piena risoluzione; e giusto, con 3 lusso con potenza 2.

Si noti che il tentativo di passare da 1/64th delle dimensioni alle dimensioni complete in un'unica dimensione sarebbe completamente diverso, poiché la scheda grafica userebbe ancora 4 pixel nella configurazione per ombreggiaturare un'area più grande e gli artefatti iniziano a essere visualizzati.

Quindi, se aggiungiamo stelle a risoluzione completa con schede più piccole, riceviamo la galassia completa:

Risultato quasi finale del rendering della galassia usando stelle a risoluzione completa

Una volta che siamo stati sulla pista destra con la forma, abbiamo aggiunto un livello di nuvole, scambiando i punti temporanei con quelli che abbiamo dipinto in Photoshop, e aggiunto un altro colore. Il risultato è stato un team di arte e ingegneria di Milky Way Galaxy, entrambi si sentivano buoni e hanno raggiunto i nostri obiettivi di avere profondità, volume e movimento, tutto senza tassare la CPU.

La nostra ultima Galassia lattea in 3D.

La nostra ultima Galassia lattea in 3D.

C'è molto altro da scoprire

È stato aperto il codice per l'app Galaxy Explorer e reso disponibile in GitHub per gli sviluppatori.

Interessati a scoprire di più sul processo di sviluppo per Galaxy Explorer? Scopri tutti gli aggiornamenti del progetto precedenti nel canale youTube Microsoft HoloLens.

Informazioni sugli autori

Foto di Fotografico Luccin alla sua scrivania È un software engineer e un appassionato di oggetti visivi fantasiosi. Era l'ingegnere della grafica per Galaxy Explorer.
Foto del capo d'arte Andy Zibits Andy Zibits è un appassionato di arte lead e spazio che ha gestito il team di modellazione 3D per Galaxy Explorer e ha combattuto per ancora più particelle.

Vedi anche