Případová studie – Vytvoření galaxie v hybridní realitě

Před odesláním Microsoft HoloLens jsme se naší komunity vývojářů zeptali, jaký typ aplikace by chtěli vidět zkušený interní týmový build pro nové zařízení. Bylo sdíleno více než 5000 nápadů a po 24hodinovém hlasování na Twitteru se vítězem stal nápad s názvem Galaxy Explorer.

Andy Zibits, vedoucí umění na projektu, a Karim Luccin, grafický inženýr týmu, hovoří o spolupráci mezi uměním a inženýrstvím, které vedlo k vytvoření přesné, interaktivní reprezentace galaxie Mléčné dráhy v Galaxy Exploreru.

The Tech

Náš tým , který se skládá ze dvou návrhářů, tří vývojářů, čtyř umělců, producenta a jednoho testera , měl šest týdnů na vytvoření plně funkční aplikace, která by lidem umožnila seznámit se a prozkoumat rozlehlost a krásu naší Galaxie Mléčné dráhy.

Chtěli jsme plně využít schopnost HoloLensu vykreslovat 3D objekty přímo ve vašem obytném prostoru, a proto jsme se rozhodli vytvořit realisticky vypadající galaxii, kde by lidé mohli přiblížit a vidět jednotlivé hvězdy, z nichž každá bude mít vlastní trajektorii.

V prvním týdnu vývoje jsme přišli s několika cíli pro naši reprezentaci Galaxie Mléčné dráhy: Potřebovali jsme mít hloubku, pohyb a pocit volumetric – plný hvězd, které by pomohly vytvořit tvar galaxie.

Problém s vytvořením animované galaxie, která měla miliardy hvězd, byl v tom, že počet jednotlivých prvků, které potřebují aktualizaci, by byl příliš velký na snímek, aby HoloLens animoval pomocí procesoru. Naše řešení zahrnovalo komplexní kombinaci umění a vědy.

Informace pro pokročilé uživatele

Abychom lidem umožnili zkoumat jednotlivé hvězdy, bylo naším prvním krokem zjistit, kolik částic můžeme vykreslit najednou.

Vykreslování částic

Aktuální procesory jsou skvělé pro zpracování sériových úloh a až několika paralelních úloh najednou (v závislosti na tom, kolik jader mají), ale GPU jsou mnohem efektivnější při paralelním zpracování tisíců operací. Vzhledem k tomu, že obvykle nesdílejí stejnou paměť jako procesor, může se výměna dat mezi procesorem<>GPU rychle stát kritickým bodem. Naším řešením bylo vytvořit galaxii na GPU a ta musela být zcela na GPU.

Začali jsme zátěžové testy s tisíci bodovými částicemi v různých vzorech. To nám umožnilo dostat galaxii na HoloLens, abychom viděli, co fungovalo a co ne.

Vytvoření pozice hvězd

Jeden z členů našeho týmu už napsal kód jazyka C#, který by na počáteční pozici vygeneroval hvězdičky. Hvězdy jsou na elipse a jejich pozici lze popsat pomocí (curveOffset, ellipseSize, elevation), kde curveOffset je úhel star podél elipsy, ellipseSize je rozměr elipsy podél X a Z a zvýšení správné výšky star uvnitř galaxie. Můžeme tedy vytvořit vyrovnávací paměť (ComputeBuffer Unity), která by se inicializovala s každým atributem star a odeslala ji na GPU, kde by byla po zbytek prostředí. K nakreslení této vyrovnávací paměti používáme DrawProcedural Unity , který umožňuje spustit shader (kód na GPU) na libovolné sadě bodů bez skutečné sítě, která představuje galaxii:

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];
 …

}

Začali jsme s nezpracovanými kruhovými vzory s tisíci částic. To nám poskytlo důkaz, který jsme potřebovali, že můžeme zvládnout mnoho částic a spustit je výkonnými rychlostmi, ale nebyli jsme spokojeni s celkovým tvarem galaxie. Pro zlepšení tvaru jsme se pokusili o různé vzory a systémy částic s rotací. Ty byly zpočátku slibné, protože počet částic a výkon zůstaly konzistentní, ale tvar se rozpadl blízko středu a hvězdy vyzařovaly směrem ven, což nebylo realistické. Potřebovali jsme emise, které by nám umožnily manipulovat s časem a umožnit, aby se částice pohybovaly realisticky a smyčce se blížily ke středu galaxie.

Pokusili jsme se o různé vzory a systémy částic, které se otáčely, jako jsou tyto.

Pokusili jsme se o různé vzory a systémy částic, které se otáčely, jako jsou tyto.

Náš tým provedl nějaký výzkum fungování galaxií a vytvořili jsme vlastní systém částic speciálně pro galaxii, abychom mohli přesouvat částice na elipsách na základě "teorie hustoty vln", která teorizuje, že ramena galaxie jsou oblasti s vyšší hustotou, ale v konstantním toku, jako dopravní zácpa. Vypadá stabilní a pevný, ale hvězdy se ve skutečnosti pohybují v rukou a z nich, jak se pohybují podél příslušných teček. V našem systému částice nikdy neexistují na procesoru – vygenerujeme karty a všechny je orientujeme na GPU, takže celý systém je jednoduše počáteční stav + čas. Postupoval takto:

Progrese systému částic s vykreslováním GPU

Progrese systému částic s vykreslováním GPU

Jakmile je přidáno dostatek teček a jsou nastaveny na otáčení, galaxie začaly vytvářet "ramena", kde se pohyb hvězd sbíhají. Mezery hvězd podél každé eliptické dráhy byly dány určitou náhodností a každá star byla přidána trochu poziční náhodnosti. To vytvořilo mnohem přirozenější rozložení star pohybu a tvaru paží. Nakonec jsme přidali možnost řídit barvu na základě vzdálenosti od středu.

Vytvoření pohybu hvězd

K animaci obecného star pohybu jsme potřebovali přidat konstantní úhel pro každý snímek a dostat hvězdy pohybující se podél jejich tří teček konstantní radiální rychlostí. To je hlavní důvod použití curveOffset. To není technicky správné, protože hvězdy se budou pohybovat rychleji po dlouhých stranách tří teček, ale obecný pohyb se cítil dobře.

Hvězdy se pohybují rychleji na dlouhém oblouku, pomaleji na okrajích.

Hvězdy se pohybují rychleji na dlouhém oblouku, pomaleji na okrajích.

Díky tomu je každý star plně popsán (curveOffset, ellipseSize, elevation, Age), kde Age je souhrn celkového času, který uplynul od načtení scény.

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);
  
}

To nám umožnilo generovat desítky tisíc hvězd jednou na začátku aplikace a pak jsme animovali jednoúčelovou sadu hvězd podél stanovených křivek. Vzhledem k tomu, že vše je na GPU, může systém animovat všechny hvězdy paralelně bez nákladů na procesor.

Takto to vypadá při kreslení bílých čtyřúhelníku.

Takto to vypadá při kreslení bílých čtyřúhelníku.

Abychom každý čtyřúhelník nakreslili ke kameře, použili jsme geometrický shader k transformaci každé pozice star na 2D obdélník na obrazovce, který bude obsahovat naši star texturu.

Diamanty místo čtyřúhelníku.

Diamanty místo čtyřúhelníku.

Vzhledem k tomu, že jsme chtěli co nejvíce omezit překreslení (počet zpracování pixelu), otočili jsme čtverky tak, aby se méně překrývaly.

Přidání cloudů

Existuje mnoho způsobů, jak získat volumetrický pocit s částicemi – od paprsku pochodujícího uvnitř objemu až po nakreslení co největšího počtu částic, aby bylo možné simulovat mrak. Pochody paprsků v reálném čase byly příliš drahé a obtížně se vytvářely, takže jsme nejprve zkusili vytvořit systém podvodníka pomocí metody vykreslování lesů ve hrách – s mnoha 2D obrázky stromů směřujících ke kameře. Když to uděláme ve hře, můžeme mít textury stromů vykreslené z kamery, která se otáčí kolem, uložit všechny tyto obrázky a za běhu pro každou kartu plakátu vybrat obrázek, který odpovídá směru zobrazení. To nefunguje ani v případě, že obrázky jsou hologramy. Rozdíl mezi levým a pravým okem ho dělá tak, že potřebujeme mnohem vyšší rozlišení, jinak vypadá ploché, aliasované nebo opakující se.

Na druhý pokus jsme se pokusili mít co nejvíce částic. Nejlepších vizuálů jsme dosáhli, když jsme doplňkově nakreslili částice a rozmazali je před přidáním do scény. Typické problémy s tímto přístupem souvisely s tím, kolik částic jsme mohli najednou nakreslit a kolik plochy obrazovky pokrývaly při zachování 60 snímků za sekundu. Rozostření výsledného obrázku za účelem získání tohoto pocitu v cloudu bylo obvykle velmi nákladné.

Bez textury by mraky vypadaly takto s 2% krytím.

Bez textury by mraky vypadaly takto s 2% krytím.

Když budeme přidávat a mít jich hodně, znamená to, že bychom měli několik čtyřúhelníku na sobě a opakovaně stínovali stejný pixel. Ve středu galaxie, stejný pixel má stovky čtyřúhelníku nad sebou, a to mělo obrovské náklady při práci na celou obrazovku.

Dělat mraky na celé obrazovce a snažit se je rozostřit, by byl špatný nápad, takže jsme se místo toho rozhodli nechat hardware, aby práci udělal za nás.

Nejprve trochu kontextu

Při použití textur ve hře velikost textury zřídka odpovídá oblasti, ve které ji chceme použít, ale můžeme použít jiný druh filtrování textury, abychom grafickou kartu získali k interpolaci požadované barvy z pixelů textury (Filtrování textury). Filtrování, které nás zajímá, je bilineární filtrování , které vypočítá hodnotu libovolného pixelu pomocí 4 nejbližších sousedů.

Původní před filtrováním

Výsledek po filtrování

Pomocí této vlastnosti vidíme, že pokaždé, když se pokusíme nakreslit texturu do oblasti dvakrát větší, rozostřou výsledek.

Místo vykreslování na celou obrazovku a ztrátě drahocenných milisekund bychom mohli utrácet za něco jiného, vykreslujeme na malou verzi obrazovky. Když pak zkopírujeme tuto texturu a několikrát ji roztáhneme o faktor 2, vrátíme se zpět na celou obrazovku a zároveň rozmazáme obsah v procesu.

x3 upscale zpět na plné rozlišení.

x3 upscale zpět na plné rozlišení.

To nám umožnilo získat cloudovou část s pouze zlomkem původních nákladů. Místo přidávání mraků v plném rozlišení namalujeme pouze 1/64 pixelů a jen roztáhneme texturu zpět do plného rozlišení.

Vlevo, s upscale z 1/8th na plné rozlišení; a správně, se 3 upscale s využitím výkonu 2.

Vlevo, s upscale z 1/8th na plné rozlišení; a správně, se 3 upscale s využitím výkonu 2.

Všimněte si, že pokus o přechod z 1/64 na plnou velikost najednou by vypadal úplně jinak, protože grafická karta by stále používala 4 pixely v našem nastavení k zastínění větší oblasti a artefakty se začnou objevovat.

Když pak přidáme hvězdičky v plném rozlišení s menšími kartami, získáme celou galaxii:

Téměř konečný výsledek vykreslování galaxií pomocí hvězd v plném rozlišení

Jakmile jsme byli na správné cestě s obrazcem, přidali jsme vrstvu mraků, prohodili dočasné tečky s těmi, které jsme namalovali ve Photoshopu, a přidali další barvu. Výsledkem byla galaxie Mléčná dráha, o které se naše umělecké a technické týmy cítily dobře a splnily naše cíle hloubky, objemu a pohybu – to vše bez zdanění procesoru.

Naše poslední Mléčná dráha Galaxy ve 3D.

Naše poslední Mléčná dráha Galaxy ve 3D.

Další informace k prozkoumání

Open source kód pro aplikaci Galaxy Explorer jsme zpřístupnili na GitHubu pro vývojáře, na kterých můžou stavět.

Chcete se dozvědět více o procesu vývoje pro Galaxy Explorer? Podívejte se na všechny naše předchozí aktualizace projektu v kanálu Microsoft HoloLens YouTube.

O autorech

Obrázek Karima Luccina u jeho stolu Karim Luccin je softwarový inženýr a nadšenec pro fantastické vizuály. Byl to grafický inženýr pro Galaxy Explorer.
Fotografie uměleckého vedoucího Andyho Zibitse Andy Zibits je umělecký vedoucí a nadšenec do vesmíru, který vedl tým 3D modelování pro Galaxy Explorer a bojoval za ještě více částic.

Viz také