Vývoj aplikací v Unreal Engine | Technický design aplikací

Vývoj aplikací v Unreal Engine | Technický design aplikací Tagy: Vývoj aplikací
| Publikováno dne

Poslední úprava dne

Vítejte v pokračování čtení knihy Vývoj aplikací v Unreal Engine psané formou blogpostů. Předešlý a zároveň prvotní příspěvek se zabýval seznámením s Unreal Engine a jeho vhodným nastavením především pro vývoj VR aplikací. Tento článek je zaměřen na volbu vhodného technického designu aplikací.

Technický design aplikace

Správně navržená aplikace se vyznačuje vynikajícím výkonem a komfortem užívání. Prvně se zaměřme na výkon. Pro příklad si vezměme cíl ve formě minimálního FPS běhu aplikace na hodnotě 90. Při 90 snímcích za sekundu máme na zprocesování 1 snímku v CPU a GPU maximálně 1000 / 90 = 11.11 milisekund. V této kapitole shrnu obecná pravidla, jimiž je třeba se držet. Analytika časové náročnosti jednotlivých operací bude probrána v kapitole vyhodnocování a výkonová optimalizace aplikací.

U aplikací pro VR headsety je nutné brát v úvahu potřebu renderování ve vysokém rozlišení hned na dvojici displejů. S tím jsou spojeny enormní nároky na výkon, které je třeba redukovat vyjma vhodného nastavení projektu rovněž prací s vhodnými zdroji včetně jejich nastavení, stejně jako případnou implementací logiky upravující chování jednotlivých komponent i v průběhu běhu aplikace.

Výkonový profil aplikací je mimo jiné odvislý od efektivity vertexových a fragmentových operací vykonávaných při renderování obsahu. Efektivita vertexových operací roste s redukcí vertexů (vrcholů sítě), případně s optimalizací vertexového shaderu. Efektivita fragmentových operací je odvislá od přiřazeného pixelového shaderu, využívaných textur a případně rozměrů renderovacího targetu.

Následující sekce této kapitoly se zaměřují na aspekty týkající se vhodného návrhu a nastavení zásadních herních mechanik a prvků z technického pohledu věci.

Levely a cachování obsahu

Aplikace pracují s množstvím různého obsahu, který je nutné velmi rychle načíst a spravovat v rámci scény. To úzce souvisí s výkonovou a paměťovou náročností aplikace. S pomocí levelů je možné držet a přepočítávat pouze obsahové zdroje vztahující se ke konkrétní části a funkci aplikace. V Unreal Engine se spravují prostřednictvím okna Window → Levels.

Levely by měly být voleny co nejoptimálněji z hlediska výkonu a uživatelského zážitku při používání aplikace. Levely mohou zahrnovat jednotlivá prostředí (= mapy / scény), úkoly (mise) i komponenty (fx efekty, zvuky, modely...). Čím je hra komplexnější a otevřenější, tím je i rozvrh levelů náročnější. Mimo optimalizaci, levely lze využít rovněž při současné práci několika lidí na jednom projektu.

Vzájemnou provázanost obsahu a levelů lze procházet pomocí nástroje Reference Viewer (dostupný po kliknutí pravým tlačítkem myši na daném zdroji). Reference viewer zobrazuje několik typů referencí (Soft, hard, management) a dalších nastavitelných parametrů.

Obsah a design levelů je nutné volit s ohledem na výkon potřebný k jejich vykreslení. Obecně je vhodné designovat aplikace tak, aby při plnění svého účelu vyžadovaly co nejméně objektů potřebných k renderování. To lze řídit vyjma vhodného designu rovněž manuálně specifikovanou logikou v C++ / Blueprint a aktivací Occlusion culling. Počet objektů potřebných k vykreslení v konkrétním čase je důležitý z hlediska generovaných draw callů do CPU. Jejich snížení lze snížit i sloučením více malých objektů (např. pomocí merge actors funkce) situovaných poblíž sebe do 1 většího objektu, ovšem je třeba počítat s případným snížením culling efektivity z hlediska potřeby přepočítávat mnohem větší síť.

Design přechodu mezi levely

Přechod mezi levely (mapami, úkoly…) vyžaduje načtení velkého množství obsahu spojeného se značnou spotřebou paměti a zdrojů. Zpravidla je v takových případech použít načítací obrazovku (loading screen). Její design je zásadní zejména u VR aplikací, kde si nelze dovolit z důvodu rizik motion sickness jakékoli neplynulé chování jejího grafického prostředí. U VR jsou v podstatě 3 možné způsoby práce s načítací obrazovkou při přechodu mezi levely:

  • Prostý přechod do plné barvy (ztmavení obrazovky) - nejpoužívanější řešení, snadno implementovatelné přes Blueprint funkci Start Camera Fade). Použít lze v případech, kdy jsme si jisti, že přechod proběhne během nízkých jednotek sekund. Při delším prostoji černo (popř jiná barva) bez jakékoli další grafiky působí pocitem “zaseknuté” aplikace.
  • Zobrazení VR splash screen - aplikovatelná skrze XR Loading Screens funkci enginu. Je snadno použitelná dokud není potřeba během splash screen jakákoli animace nebo interakce (nativně jde o černou obrazovku s logem enginu)
  • Zobrazení 1 nebo více VR Stereo vrstev - nejsvobodnější možnost, avšak její implementace vyžaduje i nejvíce práce. Umožňuje přímé měření průběhu načítání v procentech. Loading screen běží v odděleném procesu od zbytku aplikace a tedy není ovlivňována zbylými aplikačními procesy

Cachování obsahu levelů

Na výkon a rychlost načítání aplikací má zásadní vliv náročnost vykreslení obsahu. Tu lze zásadním způsobem snížit jeho zacachováním a přibalením těchto cache souborů k distribučnímu balíčku aplikace.

Podstata cachování je nejviditelnější na nízko výkonném hardwaru typu stand-alone VR headsetu Quest. Pro dosažení dobrého uživatelského zážitku (a získání Oculus certifikace nezbytné k zalistování do Oculus Store) musí být FPS aplikace 72hz, neboli maximálně 13.88ms času na snímek. Nicméně, pouhý 1 draw call vyžadující přepočet shaderů na daném zařízení může zabrat i 400ms. Takových requestů jsou přitom bez ohledu na sebelepší rozvržení levelů desítky.

Takto vysoký čas je při použit OpenGL ES Shader pipeliny (vhodná pro mobilní VR - tedy Oculus Quest a dalších stand-alone VR zařízení) důsledkem principu fungování, kdy “nové” shadery jsou defaultně kompilovány až při prvním draw volání.

Řešením k eliminaci počátečního výpočtu shaderů a s tím souvisejících důsledku (sekávání, neodpovídání aplikace atd) je provést onen přepočet již při vývoji a poté jej přiložit do balíčku aplikace. To lze docílit s využitím rozšíření (OES_get_program_binary) dostupného v Open GL ES3 standardu - který je v rámci Unreal Enginu použit prostřednictvím PSO cachovacího systému. Při integraci postupujte dle oficiální dokumentace, v principu se provádí následovně:)

  1. Otevřít “ShaderPipelineCache.cpp” Unreal Enginu (Epic Games / UE_4.24 / Engine / Source) ve Visual Studio. Zde na řádku 1415 (kód funkce FShaderPipelineCache::Open()) je třeba změnit (přepsat) “FPipelineFileCache” na “FShaderPipelineCache”.
  2. V Edit / Project Settings / Packaging povolte Share Material Shader Code a Shared Material Native Libraries
  3. V Window / Developer Tool, Device profiles přejděte do možnosti “Android” a otevřte jeho nastavení klikem na elipsu umístěnou v pravé části. Zde rozšiřte “Rendering” sekci kliknutím na tlačítko + a zvolením “r.ShaderPipelineCache.Enabled”. Hodnotu proměnné nastavte na 1.
  4. Zavřít Unreal Engine
  5. Otevřít configurační soubor pro Android enginu AndroidEngine.conf (Epic Games / UE_4.24 / Engine / Config / Android ) a na jeho konec přidat:
    [Dev.Options.Shaders]
    NeedsShaderStableKeys=true
  6. V Unreal Projektu otevřít ProjectLauncher a přidat Custom Launch Profile s názvem např. “Android PSO Cache”. Zde nastavit projekt, Cook by the book s volbou správné platformy (pro Quest to je “Android” a “Android_ASTC”), vybrat požadované levely přes okno “Cooked Maps”, v Launch sekci zvolit výchozí mapu a do “Additional Command Line Parameters” vložit “-logPSO -NoVerifyGC”, jež nám jednak umožní detekovat správnou funkci PSO cache a dále zakázáním garbage collectoru předejdou potenciálním pádům aplikace spojené s působením PSO cache.
  7. Ujistit se, že cílové zařízení je připojeno k PC (a propojeno s Unreal) a spustit building přes tlačítko “Launch this profile” nově vytvořeného Launch profilu. Vyjma buldu se aplikace v cílovém zařízení i spustí.
  8. Vygenerovat PSO cache na cílovém zařízení (Oculus Quest). Přes adb příkaz “adb shell mkdir -p /**pathToProject**/ProjectName/Saved/CollectedPSOs” si potvrdíme existenci složky. Po pár spuštěních aplikace by měl být v dané složce soubor soubor upipelinecache file.
  9. Vytvořit si někde v počítači (např: D:/PSOCaching) složku PSOCaching. Najít dvojici souborů *ShaderStableInfo…scl.csv* dostupné ve složce Unreal Projektu (*ProjectName*/Saved/Cooked/Android_ASTC/*ProjectName*/Metadate/PipelineCaches a zkopírovat je do v tomto kroku vytvořené PSOCaching složky. Do téže složky zkopírovat i “UPIPELINECACHE file” z kroku 8.
  10. Do složky PSOCaching z kroku 9 si vložit zástupce souboru “UE4Editor-Cmd.exe” nalezitelného v (Program Files/Epic Games/UE_4.XX / Engine / Binaries / Win64). Otevřít vlastnosti zástupce (pravé tlačítko myši → vlastnosti) rozšířit attribut Target o cestu k Unreal projektu a jeho PSOCaching souborům (např:”*cesta zastupce*” D:/Project1 -run=ShaderPipelineCacheTools expand D:/PSOCaching/*.rec.upipelinecache D:/PSOCaching/*.scl.csv *ProhjectName*_GLSL_ES3_1_ANDROID.stablepc.csv”. Následně daný zástupce spustit, čímž proběhne vytvoření souboru “stablepc.csv” ve složce PSOCaching.
  11. Překopírovat “stablepc.csv” z kroku 10 do složky obsahující vybuildovanou aplikaci (/Build/Android/PipelineCaches), přičemž složku “PipelineCaches” je třeba vytvořit ručně před vložením.
  12. Rebuidovat aplikaci (File → Package Project → Android → Android (ASTC)

Soubor “stablepc.csv” není třeba aktualizovat průběžně, avšak jeho aktualizace je nutná u verzí určených k distribuci (produkční verze).

Osvětlení scény

Osvětlení (lighting) je prvkem s nejvyšším dopadem na výkon. V rámci nasvětlení je možné kombinovat 3 typy světel odlišné v chování a výpočetní náročnosti - statické, stacionární a dynamické ( Static, Stationary a Dynamic). Pro dobrý výkon aplikace je zásadní správná volba, nastavení a rozvržení všech světelných zdrojů.

  • Static lights

    Statická světla jsou nejméně výpočetně náročnou metodou osvětlení scény → proto by jich měla být převaha. Při statickém osvětlení je hodnota světlosti zapečená v textuře. V rámci runtime je tedy při statickém osvětlení fixní výkonová hodnota potřebná k renderu jakéhokoli počtu těchto světel. Zapečení se provádí během vývoje, v Unreal Enginu (Build → Lighting).

    Statická světla umožňují nastavení všech tradičních parametrů nasvětlení, jako je teplota barvy, intenzita i tvar světelného zdroje (Point, Directional, Spot, Rectangle). Také mohou počítat se stíny a nepřímým nasvětlením. Zkušený vývojář v práci s nasvětlením scény dokáže dosáhnou velmi přesvědčivých výsledků pouze s využitím statických světel v rámci scény.

    Statické osvětlení je volbou vysokého výkonu, avšak "nízké kvality", jelikož nijak neovlivňuje dynamické objekty. U těch Unreal jen přibližně odhaduje a poté ukládá okolní osvětlení.

  • Dynamic lights

    Dynamics Lights provádí kalkulaci v runtime. Proto je vhodné jejich počet minimalizovat na nezbytné minimum. Reflektuje rovněž dynamické stíny, které jsou výkonově velmi náročné na výpočet. Proto je vhodné generování stínů od těchto zdrojů (je-li to možné) deaktivovat [provádí se v nastavení "cost shadows" konkrétního světla]. Určité stíny (např. od listů stromů pohybujících se větrem) lze uměle "napodobit" animací textury materiálu. Tu lze nanášet na celý objekt (jako materiál), stejně jako konkrétní část (vyžaduje materiálový node HeightLerp) pomocí štětce (Paint).

    U dynamických světel neplatí (četl jsem, nemám ověřeno) pravidla occlusion cullingu - jejich přítomnost vstupuje do výpočtů vždy.

    Normálně herní enginy zjišťují které draw calls interagují se světly přes simple volume intersection test. Na základě dosahu působení světla může každý drawcall zjistit, zda potřebuje vyvolat kód pro výpočet osvětlení na konkrétním objektu od konkrétního světla. To částečně souvisí s problematikou dynamických stínů. Ty jsou implementovány s "Shadow map rendering" technikou. Tato metoda vyžaduje extra renderovací průchod všemi působiteli (vrhači) stínů, kteří jsou v oblasti ovlivňování stínů. Výkonový důsledek na frame je v tomto případě značný. Proto je doporučené nastavit maximální renderovací vzdálenost pro dynamická světla + snažit se snížit jejich vliv na co nejmenší potřebnou oblast [Okno nastavení světla → sekce performance / Max Draw distance].

  • Stationary lights

    Stacionární světla maji chování statických i dynamických světel. Vrhají světlo na všechny objekty a objevují se v povrchových detailech objektů. Mohou také zahrnovat před-počítané odrazové osvětlení (pre compute bounce lighting).

Poznámky k osvětlení scény

  • Minimalizovat dynamické osvětlení na nezbytné minimum (aktivovat je jen v případě potřeby). Přínosem je i zakázat ovlivňování stěn a dalších objektů dynamickými světly.
  • Kdykoli stacionární nebo dynamická světla se překrývají, renderer potřebuje udělat spoustu extra práce. Jestliže se vzájemně překrývají více jak 4 stacionární světla, Unreal je automaticky překonvertovává na dynamická světla (pokud se to děje, je v Unrealu viditelné upozornění).
  • Při zapékání světel je důležité vložit reflection captures do prostoru - provede se 360° snapshot snímek scény a jeho světelné detaily se aplikují do dnyamických a statických objektů. Důležité je, aby reflection captures objekty nebyly nastaveny na snímání při každém framu.
  • Při pohybu statického tělesa s vytvořenou lightmapou je daná lightmapa invalidována - pozor na to!

V současné době mobile forward lighting v Unreal Engine nepodporuje volání dynamických světel. Příspěvek statických světel je předem vyčleněn a jsou také ukládány do mezipaměti, což pomáhá při optimalizaci.

3D modely

3D modely jsou sítě polygonů definující tvar objektu. Tyto sítě jsou složeny z vrcholů (vertex) a ploch (faces). Plochy se rovněž nazývají polygony. S rostoucím počtem vrcholů roste exponenciálně i náročnost vykonávání vertexových operací. Detailní náhled do problematiky 3D modelů je v článku Jak na výkonnostní optimalizaci modelů a její automatizaci?.

U počtu vrcholů je nutné si uvědomit, že jsou například brýlemi Oculus Quest zpracovávány v rámci 1 streamu hned 2x (poprvé při binování a podruhé při vykreslování), a tedy jejich počet má v hned dvojitý dopad na výkon.

  • Binování (Binning) - Během binování, zjednodušená verze vertexového shaderu je exekuována k výpočtu pozice primitivu a přiřazení odpovídajícího dělení na cíli vykreslení.
  • Vykreslování (Rendering) - Během vykreslování jsou znovu exekuovány všechny vertexové shadery, které byly přiřazeny k binování, a to pro výpočet jakýchkoli interpolantových hodnot použitých fragmentových operací, následovaných provedením exekuce fragmentového shaderu.

Modely by měly být definovány sítěmi s rozumným počtem vertexů. Cílení na jejich nejnižší možný počet při udržení požadovaného tvaru objektu nicméně není zásadním - daná úspora počtu vertexů oproti běžnému optimalizovanému stavu nebude z pohledu výkonu zásadní a tedy není časově efektivní.

U vývoje VR cíleného na PC lze používat i pokročilejší funkce na správu polygonů, jako je například Tessellation.

Unreal Engine nabízí hned 2 základní a jednoduše použitelné funkce při optimalizaci počtu vertexů / polygonů. První je možnost automatizované redukce počtu polygonů, druhou je aplikace LOD (level of details) - detaily objektu (= počet polygonů) roste a klesá se změnou vzdálenosti objektu od kamery. Vyjma ručního nastavení lze LOD aktivovat i hromadně.

Nastavení a volba materiálů

Volba materiálů je odvislá od požadavků na vizuální kvalitu a cílové platformě. Obecnou problematiku rozlišení textur, vrstevnosti a dalších atributů jsem rozebral v samostatném článku CAD modely - Jak na výkonnostní optimalizaci a její automatizaci?. Zde se budu zabývat pouze typy renderingu + vhodným designem počtu používaných materiálů a materiálových shaderů.

Blend módy materiálů

Z hlediska výkonové optimalizace, kdekoliv, kde je to možné, by se měly používat neprůhledné materiály, viz Opaque Rendering. Příklady, kde to vhodné není, jsou veškeré objekty nepůsobící s plným materiálem přirozeně (vlasy, vegetace, okna...), nebo by vyžadovaly k obstojnému vykreslení enormního počtu polyonů vedoucích k vyššímu zatížení (listí na stromě). Dalšími příklady mohou být různé řezy objekty, otvory, nebo různé typy průhledných stěn. Blend mód (metoda renderingu) se nastavuje v Detail okně, sekci Material, daného materiálu.

  • Opaque Rendering (Neprůhledné vykreslování)

    Určené pro plné objekty. Vyznačuje se nejvyšší výkonovou nenáročností. V módu hrubého třídění zepředu dozadu je možné vyhnout se výpočtů prováděných pixelovým shaderem pro uzavřené pixely.

  • Masked Rendering (Maskované vykreslování)
    • Určený pro objekty, které mají masku s pixely buď o 100% neprůhlednosti nebo naopak 100% průsvitnosti (nic mezi tím).
    • Pokud je povolen MSAA, Unreal Engine 4 dělá víc než jen jednoduché instrukce při zabití nebo oříznutí ve pixelov0m shaderu, což vede k binárnímu rozhodování na úrovni pixelů. V závislosti na úrovni levelu nastavení MSAA lze pozorovat více odstínů a jejich mírně pozvolnější přechody (propojení MSAA a hodnoty alfa).

      Masked Rendering umožňuje nastavení určitých vlastností pomáhající ke zvýšení výkonu, ale častým nežádoucím artefaktem je "kostrbatost" hran. Tomu se lze vyhnout určitými modifikacemi, jako je např. metoda Dithered Masked.

    Dithered masked

    Masked Rendering s shader ditheringem je modifikací Masked renderingu. Zvládá více odstínů, avšak za cenu vysokofrekvenčního šumu (je znatelně viditelný). K jeho částečnému potlačení lze dithering měnit přes několik framů, ovšem získáme při tom i jakýsi efekt třpitu. Dithered masked není příliš optimální při Fixed Foveated Rendering - skok v rozlišení je mnohem viditelnější s vysokofrekvenčním vzorem.

  • Translucent Rendering (Průsvitné vykreslování)

    Režim prolnutí (blend mode) pro objekty se stavem průhlednosti mezi plnou průhledností a plnou neprůhledností. Má největší dopad na výkon, a je tedy nejméně doporučován.

  • Alpha Transparency, Additive and Modulate (Alfa průhlednost, aditivum a modulace)

    Režimy míchání, které jsou výkonnější alternativou k průsvitnému vykreslení. Addictive může pouze zesvětlit materiál, zatímco Modulate může pouze ztmavit materiál.

Volba materiálů pro maximální výkonovou optimalizaci

S rostoucí složitostí materiálů roste rovněž náročnost fragmentových operací. Jedním zdrojem výkonnostního dopadu při těchto operacích je načítání textury z paměti. U Questu se doporučuje použít dvě nebo méně textur na materiál.

Pro maximální výkon je potřeba minimalizovat potřebu přepínání materiálových shaderů. V praxi to znamená používat méně materiálů, které jsou tedy nakonec používány častěji. To dělá optimalizaci efektivnější a umožňuje GPU pracovat efektivněji, protože nepotřebuje přepínat shadery tak často při renderování mnoha materiálů. To hlavně ovlivňuje CPU výkon, a znatelné to je zejména na nízkovýkonném PC a mobilním hardware. Závislost potřebného času na změnu materiálu na základě jeho typu je na grafu níže. Strmost křivek je dána typem draw calls.

Graf - Závislost potřebného výpočetního času na změnu materiálu. Screenshot pořízen z kurzu Unreal Engine.

Další poznámky

  • Vyhněte se použití textur, pokud je skutečně nepotřebujete. Nahradit je lze stálou barvou nebo jednoduchou matematickou operací
  • Pokud materiál používá lit shader a spectacular highlight není potřeba, zaškrtněte “Fully rough” checkbox v detail okně materiálu. To není stejné jako nastavení “roughness” pinu materiálu s hodnotou 1, Fully rough checkbox využívá výhody skutečnosti že roughness je 1 a algebraicky zjednodušuje výpočet zrcadleného nočního světla. Rovněž zkontrolujte případnou nutnost zaškrtnutí boxu pro vysoce kvalitní odrazy v sekci podrobností o materiálu - funkce je výpočetně náročná a tedy měla by být užívána střídmě. Souvisí to s spectacular highlights. UE4 používá cube mapy k tvorbě iluze odrazu pro lesklé povrchy. Tato funkce je dostupná pro Quest i Rift. Pro obě platformy je nicméně implementována rozdílně z důvodu začlenění rozdílnosti v hardwarech.
  • Dobře využijte normálovou mapu pro materiály používající lit shading model, ale normálovou mapu nepřidávejte, pokud chcete, aby měl objekt dokonale rovný povrch

2D Graphics User Interface (GUI)

GUI je dynamické grafické rozhraní, jehož prostřednictvím hráči mohou interagovat se hrou (ovládání, změna nastavení…) stejně jako být hrou informováni o důležitých událostech.

Typ, množství a struktura GUI elementů se volí dle designu aplikace. Zlatým pravidlem je držet množství a rozsah GUI co nejmenší možný, jelikož každé GUI využívá render target k vykreslení komponent do obrazovky a tedy alokuje určitý výkon a paměť aplikace. U mobilních zařízení je důležitý i vztah se spotřebou energie.

V Unreal Engine se pracuje prakticky se 3 technologickými formami GUI:

  1. Text Render Actor (Izolovaný UI prvek)
  2. Unreal Motion Graphics (UMG)
  3. Stereo Layer (SL)

Zvláštním způsobem umístění GUI v prostoru je head-up display neboli HUD. Jak název vypovídá, jde o svázání uživatelského rozhraní s kamerou hráčského objektu Player Pawn.

Text Render Actor (Izolovaný UI prvek)

Použití Text Render Actoru dává smysl v případě samostatného jednoduchého textu (vypsání názvu, informace) umístěného v prostoru virtuálního 3D světa. Umožňuje použití Signed Distance Fonts neboli SDF fontů. Ty fungují na principu zakódování textu do textury, čímž je umožněno využití texture samplingu v GPU k vyhlazení hran znaků → text má ostré hrany při pohledu z jakékoli vzdálenosti. Mimo ostrosti, vykreslení je rychlejší a umožňuje mask rendering s použitím anti-aliasing. Nastavení se provádí při importu fontu do Unrealu [Pravé tlačítko myši → User InterfaceFont] (pro použití v text render actoru), a to následným nastavením možností:

  • Font Cache typeoffline
  • Create Printable Onlyenabled
  • Used Distance Field Alphaenabled

Příklad implementace je součástí assetů Unreal - v okně “Engine Content” vyhledejte pojem “textmaterial”.

  • Předdefinované SDF fungují dobře pro Temporal Anti Aliasing.
  • U MSAA je nutné změnit materiál na typ masked.

Unreal Motion Graphics (UMG)

UMG (Unreal Motion Graphics) je moderní a rozsáhlý toolset pro tvorbu uživatelského rozhraní v Unreal Engine. Vhodný je tedy pro tvorbu jakékoli uživatelského rozhraní. Technicky je postaven na osvědčeném konceptu canvas elementů (canvas je na vrcholu hierarchie UI elementů), v případě Unrealu jde o Slate UI Framework. Potenciálně časově náročnější implementace je zde vykompenzována nižším počtem draw calls odrážejícím se zpravidla na lepším výkonu aplikace.

UMG je spravována prostřednictvím Widget komponenty. Z pohledu časování je widget nejprve vyrenderován na render target a ten až poté zobrazen v 3D prostoru. Jeho aktualizace poté mohou být vzorkovány již běžným vykreslením rámečku a tím ušetřit značné množství času.

UMG + Mip-mapy

V případě používání textur v rámci canvas elementů, textura by měla vždy obsahovat mipmapy. Ty mohou být generovány automaticky v UMG v čase po dokončení vykreslení a před jeho použitím ve 3D prostoru (MipMap box pro zaškrtnutí). Mip-map textury vyžadují dodržování velikostního poměru 2x (256,512,1024,2048…). Vyšší než 2048 často v souvislosti s rozlišením běžných obrazovek nedává smysl. Vygenerovaný sheet mipmap zabírá stejně paměti jako originální textura.

Menší mipmapy vždy vypadají lépe pokud jsou dál a větší mipmapy naopak pokud jsou blíže. Hladké přechody mezi jednotlivými mipmapami jsou dosaženy použitím Trilinear samplingu. Pro lepší čitelnost z úhlů sloučí anisotropic filtering.

Při UMG je nutné počítat s určitým rozostřením hran při velkém zmenšení / přiblížení vlivem minifikace textur (znaky ovlivňují zlomky pixelů než celé pixely). Distance field math funguje dobře pro hrany, ale nefunguje dobře, když je více hran v pixelu. V takovém případě může nastat velmi drsný aliasing. Za cenu určité složitosti a vlivu na výkon lze kvalitu částečně navýšit vylepšením Distance field Shaderu.

Stereo Layers (stereofonní vrstvy)

Stereo Layers jsou renderovány do 3D světa paralelně ve vlastním renderovacím průchodu mimo zbytek procesů aplikace. Pointa tohoto je, že compositor nikdy “nezmešká” žádný snímek - zkrátka se nestane, že by nestihl vykreslit snímek v přiděleném čase X ms definovaným minimálním vyžadovaným FPS (obvykle 13,88 ms pro Quest / 11,11 ms pro Rift S). Tato vlastnost je cenná hned v několika typech použití:

  1. Aplikace s vysokým vlivem uživatelské svobody → riziko přehlcení scény prvky
  2. UI během načítání úrovní / přepínání levelů (lze se tím vyhnout potřebě vybělení do běla při přechodech)

Výhody používání Stereo Layers jsou vykoupeny mnohdy náročnou správou a promísení Stereo Vrstev se zbytkem 3D obsahu z důvodu stereo konvergence (2 objekty jsou renderovány ve 2 rozdílných rovinách, přičemž existují (musí se sbíhat) ve stejném prostoru obrazovky) - zkrátka, aby všechny prvky spolu seděly a ladily. Vrstev je možné mít více a seřazovat je na základě hloubky.

Head-up display (HUD) ve VR

Head-up display je UI zobrazované přímo před obrazovkou - kamerou objektu Player Pawn a zároveň sledujícím její pohyb. Mnohdy je toto UI vnořeným objektem Player Pawnu.

U HUD je velmi důležitý design zobrazení UI. Nejoptimálnější je zobrazení co nejblíže středu displejů. Čím je UI zobrazováno dále od středu, tím jeho čitelnost klesá a je pro oči namáhavější (nutnost pozorovat něco v “periferii”). Navíc, v případě zobrazení poblíž hran obrazovky při aktivním fixed foveated rendering (FFR) bude dané UI renderováno ve sníženém rozlišení.

Jestliže “rovinu vykreslování” oddálíme od kamery, je nutné řešit potenciální kolize mezi UI a okolními předměty prostoru. Pevné svázání pohybu kamery s pohybem UI může navíc působit Motion Sickness - vhodným řešením je aplikovat na UI pohyb volný, lehce opožděný za pohybem kamery (jakoby UI mělo určitou hmotnost, jež je nejdříve nutné pozvolna rozpohybovat a poté zastavit).

V HUD lze používat Text Render Actory, HUD i Stereo Layers.

FX / Particles

Vizuální efekty (FX / VFX) s využitím particles (částic) se vyznačují vysokým počtem průhledných překrývajících se sprites (2rozměrných bitmap) počítaných v GPU. Typickým příkladem využití particles je například oheň. Pokud je množství particles nad rámec výpočetních možností GPU, dochází k tzv. overdraw problému.

Při využití ve VR je nutné brát v úvahu prostorový nesoulad mezi způsobem pohledu do prostoru virtuální reality (prostorové vidění vlivem 2 displejů VR brýlí) a 2D sprites v něm zobrazených. Plochy sprites jsou vždy natočeny směrem k uživateli, což funguje skvěle, dokud je na ně nahlíženo ploše (standardní monitor) - ovšem v rámci dvojice displejů VR brýlí je plochost sprites pozorovatelná. Z toho důvodu je nezbytné vyhýbat se renderování větších sprites v blízkosti kamery. Se zmenšujícím se rozměrem particles klesá i pozorovatelnost i jejich problému s plochostí. Použitelné jsou i emitory částic (particle emmiters). které vytvářejí částice v objemu.

Z hlediska výkonu je optimální volbou preference více materiálových efektů a menším počtem vrstvených particle efektů.

Post-processing

Post-processing je silnou zbraní při dotváření krásných a působivých vizuálů, avšak řekne si za to o podstatnou část výkonu. Při VR je navíc vykonáván hned 2x - pro každé oko (displej) samostatně. Vhodné nastavení post-processingu je hlavně o citu a testování - časy post-processingu pro jednotliv0 displeje (View 0 a 1) jsou zjistitelné při profilování. Někdy postačí k zásadnímu zvýšení výkonu pouhá změna typu metody daného post-preocessingu, jindy optimalizace může vyžadovat více práce, někdy až nutnost rozloučit se s daným post-processem. Post-processing se nastavuje v rámci aktoru "PostProcessingVolume".

  • Pokud je nutné používat Bloom method, volit metodu "Standard", která je oproti "computionally" výkonově značně úspornější

Současný vývoj pro Mobile a PC VR

Při vývoji na platformy / VR headsety s diametrálně odlišným výkonem, rozlišením obrazovky a podporovanými funkcemi se využívá defaultních napříč platformami kompatibilních řešení a dělení zdrojů na základě aktuálního zařízení se provádí pouze v nezbytných a specifických případech pro konkrétní platformu. Zde je pár příkladů pro Mobile VR (Quest) a PC VR (Rift):

  • Pokud je požadováno osvětlení, obě platformy by se měly spolehnout na lightmaps pro statické objekty scény, které se nepohybují
  • Rift bude moci používat postproces, mít více dynamických světel, stínů, mozaikování atd.
  • Quest by neměl používat jinou sadu materiálů, ale odkazovat na textury stejného nebo nižšího rozlišení s nižší kvalitou osvětlení. Důvodem je Rift a Quest provozuje dva různé renderery.
  • Pokud je potřeba řešit výkon GPU snížením nákladů na shader nebo materiální zdroje, oddělenost materiálů pro Rift a Quests zabrání náhodné úpravě jedné platformy při pokusu o optimalizaci druhé.
  • Quest by měl také použít jinou sadu sítí modelů (používat sítě s nižším počtem vrcholů).

Testování, měření výkonu a výkonová optimalizace

Vhodné nastavení projektu v Unreal Engine a dodržení optimálních postupů v rámci technického designu aplikace je základním předpokladem k dobrému výkonu běhu aplikace, který je však nezbytné ověřit řádným testováním a měřením. Získaná data jasně ukážou, jak si konkrétní prvky aplikace stojí z hlediska výkonu → čímž se získá seznam procesů a zdrojů, na které je třeba se zaměřit z hlediska potřebné výkonové optimalizace.

Unreal Engine je tzv. WYSIWYG (What you see is what you get) editor, což znamená že poskytuje několik režimů náhledu usnadňujících vývoj, rychlé iterace i zkoušení přímo v enginu, aniž by bylo nutné paralelní spuštění aplikace na cílovém zařízení. Tyto možnosti značně usnadňují testování, nicméně nelze jej brát jako náhradu testování (především v ohledu výkonu) na cílovém zařízení.

Emulovaný typ zařízení při běhu aplikace v Unreal Engine lze nastavit v Settings → Preview Rendering Level (uvnitř sekce Scalability). Dostupné možnosti jsou “Shader Model 5” (pro PC), “Android ES 3.1” a “iOS”.

Velmi přínosnými jsou “Optimization Viewmodes” dostupné prostřednictvím nabídky “View Modes”. Jejich dostupnost a správnost poskytovaných dat je ovšem odvislá od použitého shaderu, respektive emulovaného zařízení v enginu. Např. hned první mód “Light complexity” počítající výkonnostní náklad na osvětlení jednotlivých pixelů všemi přispívajícími dynamickými světly je použitelný pouze v emulacích s Shader Model 5 (PC, konzole) - ostatní platformy používají rozdílné metody kalkulování světelnosti, přičemž daný viewmode tuto skutečnost nerespektuje. Naproti tomu, vizualizace “Shader Complexity” zobrazuje celkový počet shaderových instrukcí na 1 pixel vykonaných materiálem bez započítání osvětlení a je tedy použitelná při vývoji na jakoukoliv platformu.

Základní analytika přes konzolové příkazy

Unreal Engine umožňuje přístup k diagnostickým metrikám enginu v runtime stavu prostřednictvím nízkoúrovňového obecného systému podobnému příkazovému řádku ve Windows, nebo terminálu v Mac. Nazývýme jej konzole, a její příkazová řádka lze otevřít na PC klávesou '`'.

Základní konzolové příkazy pro sledovani výkonu

  • Stat Unit poskytuje frame time informaci v ms (Frame, Game, Draw, GPU), kdy Frame značí celkový čas framu, Game (označitelný rovněž jako Main) čas zprocesování herních mechanik (herní logika, fyzika, networking, blueprints), Draw značí čas renderingu a GPU jednoduše čas GPU.

    Frame (total) time by měl být nejvyšší hodnotou z hodnot game, draw a GPU. Pokud GPU čas je blízko Frame času, a zbylé Game a Draw časy jsou nižší, pravděpodobně dochází k tzv. GPU bottleneck. Při analýze je třeba počítat s tím, že čas CPU měří rámec N, zatímco čas GPU může měřit N-1.

  • Stat Unitgraph zobrazuje Stat Unit hodnoty z posledních 10 sekund ve formě grafu.
  • Stat FPS zobrazuje počet framů za sekundu (FPS = frame per second) a čas 1 framu v ms (jde o inverzní hodnoty (1000 / FPS)). Při analytickém pohledu se bere hodnota času na jeden frame, s FPS se nepracuje - FPS se bere pouze jako informační hodnota.
  • Stat Game zobrazuje CPU časy v rámci Game vlákna.
  • Stat Engine statistiky se hodí pro sledování počtu polygonů sítě, času framu a času synchronizace framu (čas, kdy herní vlákno (game thread) čeká na dokončení renderovacího vlákna)
  • Stat Scenerendering informuje o čase práce CPU při renderingu.
  • Stat GPU poskytuje hodnotu pracovní zátěže GPU, což jsou náklady na všechny draw calls / GPU výpočetní operace vztahující se k určité kategorii definované v systému Unreal Engine (postprocessing, hairRendering, UI…). Tyto statistiky jsou dostupné při používání grafického API Vulkan.
  • Profile GPU zachycuje čas trvání vykreslování GPU ve strukturované formě definované typem operací a systémů

Veškerá data získaná prostřednictvím konzolových příkazů lze posílat i do cílového zařízení. V případě Androidu se používá adb (Android Debug Bridge). Příkaz na posílání dat z profilovacího systému Unrealu do android aplikace je: adb shell “am broadcast -a android.intent.action.RUN -e cmd ‘stat unit’”, kde stat unit lze nahradit jakýmkoli jiným konzolovým příkazem. K diagnostickým datům se však lze p5i pou69v8n8 Oculus Quest dostat i napřímo, a to pomocí na pozadí běžící aplikace OVR Metrics Tool.

Analytika pomocí analytických nástrojů

Veškerá data o běhu aplikace poskytovaná Unrealem lze vizualizovat a spravovat prostřednictvím externích a interních nástrojů. Velmi jednoduché je používání nativního nástroje pro profilování procesů zvaného Unreal Frontend [Epic Games / UE_4.XX / Engine / Binaries / Win64 / UnrealFrontend.exe]. Externí nástroje jsou časově náročnější na implementaci, avšak mnohdy umožňují detailnější náhled na procesy. Mezi kvalitní bezplatné nástroje patří:

  • Systrace - obecný CPU výkonostní nástroj, který je součástí Android SDK - buď nainstalovaný v Unreal Engine [Engine / Extras / Android Works / Win 64] nebo v rámci NVPacku [C:/NVPack /...]. Spouští se souborem "monitor.bat", výstup je ve formě interaktivní web stránky s daty. Lze s ním analyzovat i GPU (před spuštěním aplikace v Systrace je třeba aktivovat pomocí příkazu adb shell ovrgpuprofiler -e a poté lze v Systrace zaškrtnout volbu GPU RenderStage). Samozřejmostí je možnost současného trackování CPU a GPU.

    Systrace umožňuje rovněž používání maker, příklad makra je na řádku 4266 souboru “Epic Games / UE_4.XX/Engine/Source/Runtime/Launch/Private/LaunhEngineLoop.cpp”.

  • Render Doc - open-source projekt, použitelný pro profilování aplikací používajících OpenGL, Vulkan nebo DirectX grafické API. Render Doc je po instalaci dostupné jako samostatná aplikace + plugin v Unreal Engine. Po povolení jeho pluginu se objeví ve view okně vpravo nová Render Doc ikona pro zachycování snímků (capturing frames). Data jsou v nástroji roztříděná, velice podrobná a snadno analyzovatelná. Draw calls související se hrou jsou pod sekcí “Scene”, draw calls mimo tuto kategorii pravděpodobně souvisí s debugovacím systémem.

    Render Doc lze používat i při profilaci aplikace běžící na cílovém zařízení. V takovém případě se Render Doc spustí samostatně (např. přes ikonu v nabídce start) a dole vpravo zvolí cílová platforma namísto “Local” (pro viditelnost zařízení je nutné jej mít propojené s PC). Dále se v záložce “Launch Application” přiřadí Executable path aplikace určené k debugování. Pro správnou funkci je nezbytné mít projekt neaktivní pro distribuci (Edit → Project Settings / Packing → For Distribution [disabled]) v Unreal. Poté již stačí spustit aplikaci tlačítkem Launch a po navázání komunikace Render Docu s aplikací kliknout na tlačítko “Capture frame”.

Poznámky k využívání profilovacích nástrojů

  1. Mějte základní znalost o tom, jak nástroje data sbírají a presentují. Některé nástroje mohou data modifikovat pro usnadnění jejich čtení (např. převedení hodnot do průměrných), čímž dojde k “vyhlazení extrémních hodnot” a tím skrytí problémů.
  2. Při profilování eliminujte přítomnost externích faktorů ovlivňujících výkon. Mimo logickému vyhnutí se běhu náročných nesouvisejících aplikací a procesů v zařízení během profilování, je to zejména následující:
    • Dynamic clock system - ve výchozím nastavení zvýší takt CPU a GPU, pokud aplikace nesplňuje snímkovou frekvenci nebo naopak sníží, pokud aplikace běží velmi dobře a nepotřebuje běžet na aktuální frekvenci. Funkci taktování lze pro Oculus VR headsety ovlivnit jejich nastavením na vysoké hodnoty (4 nebo 3) - příkazy “adb shell setprop debug.oculus.cpuLevel 4” a “adb shell setprop.oculus.gpuLevel 4”. Uzamčení těchto hodnot umožňuje konzistentní získávání dat profilerem v průběhu času.
    • HMD pozice - uzamčení kamery hráče (pohyb a rotace) během profilování tak, aby data čtená profilerem nebyla ovlivňována případným jiným umístěním / pohybem kamery. Uzamčení je jednoduše možné pomoci Blueprint nodu “Enable Position Tracking”.

Vyhodnocování výsledků

Výstupem profilování je řada dat. Základní stěžejní hodnotou je čas práce CPU a GPU. Celkový čas vykonávání musí být nižší než hodnota 1000 podělená minimálním požadovaným FPS.

Při pohledu na výsledky je vhodné si kvalifikovaně odhadnout, zda aplikace je vázána na hlavní vlákno (main) nebo vykreslovací vlákno (draw). V obou vláknech totiž může docházet ke zpoždění (bound), a od toho se odvíjících tzv. CPU a GPU bottleneck. Main vlákno je relevantní CPU, kdežto Draw vlákno GPU.

Čas práce CPU je ovlivňován zejména počtem draw calls. Při vývoji na Oculus Quest je doporučené držet počet multiview draw calls pod 50. Využítí CPU je dostupně pod konzolovým příkazem „stat game“.

Jestliže aplikace nedosahuje požadované výkonnosti, začíná proces optimalizace. Dle dat z profilovacích nástrojů se dohledá kritické procesy a posléze možnosti jejich úprav (změna nastavení, redukce kvality atd). Po tomto provedení se ověří změny novým testem.

Optimalizace se provádí z důvodu vzájemné provázanosti zpravidla prvně pro GPU a až poté pro CPU procesy.

Doposud nepoužité části původního článku

Unreal Engine je moderní software pro vývoj her a aplikací založených na potřebě realističnosti, neomezené práce s 3D objekty a renderem v reálném čase. Vyjma herního průmyslu, velké popularity dosahuje v architektuře, automotive, filmovém průmyslu, vzdělávání, tréninku, simulacích, XR aplikacích nebo vysílání živých událostí. Celý souhrn využití naleznete na oficiálním webu enginu. V principu jde o obecný nástroj, v němž lze tvořit téměř cokoliv.

Za největšího konkurenta Unreal Engine lze považovat obdobný engine od Unity. Mezi oběma programy existuje celá řada rozdílů, tím z počátku nejviditelnějším je rozdílý programovací jazyk - v Unreal engine většina tvůrců používá vizuální programovací prostředí Blueprint, jež se může pro milovníky kódu jevit nepřehledným. Principy programování a toku kódu jsou zde však zachovány a rychle si lze zvyknout. Alternativou Blueprint je výkonově optimálnější programování v C++.

Výhodou Unreal engine je široká podpora práce s modely a materiály. Vyjma oficiální dokumentace lze vědomosti čerpat i z obřího množství informací na internetu. Nutno však zmínit, že pro přístup ke všem zdrojům je nezbytné stát se ověřeným vývojářem Unreal Engine. Toho docílíte přihlášením se do účtu Epic Games a propojením svého licencovaného účtu Epic Games se svým GitHub účtem. Spojením všech zdrojů mám přitom na mysli i přístup ke kompletnímu kódu herního enginu - Unreal Engine je totiž Open Source. V jeho kódu si můžete cokoliv upravovat a poté z upraveného kódu vybuildovat pomoci Visual Studia customizovaný Unreal Engine. Například upravenou verzi Unreal enginu zaměřenou na virtuální realitu má na svém GitHubu Oculus. Samotnou tvorbu pro VR však podporuje i standardní build Unrealu.

Unreal Engine si může kdokoliv legálně stáhnout a vyzkoušet. Do prvního vydělaného $1 milionu je jeho používání zdarma. Přesto, mnozí vývojáři a tvůrci se výběrem vhodného herního enginu pro jejich projekt nezabývají a automaticky volí Unity. Abych jim možná usnadnil, možná ztížil volbu, průběžně sepisuji a aktualizuji článek s rozdíly mezi Unreal a Unity. Sám jsem totiž nucen v závislosti na typu VR produktu používat oba enginy. Jestliže jste rozhodnuti se naučit pracovat s Unrealem, na webu https://learn.unrealengine.com naleznete stovky až tisíce hodin vzdělávacího videoobsahu.

YouTube kanál s tipy a triky pro Unreal Engine

Při své práci se zaměřuji především na volbu správných nástrojů a procesů pro maximálně efektivní tvorbu aplikací využívajících real-time 3D prostředí. Má práce zpravidla končí po pilotním projektu a pár prvních projektech, behem nichž jsou veškeré procesy nastaveny a ideálně automatizovány tak, ať jsou delegovatelné a škálovatelné. S tvorbou procesů jsou svázané i dokumentace. Aby byly co nejjednodušší, rozhodl jsem se pro tvorbu krátkých (maximálně 3 minutových) video ukázek obecných možností v Unreal Engine, na něž z dokumentací odkazuji. Tyto ukázky zveřejňuji na YouTube kanálu GameArter, v playlistu Unreal Engine - Quick tips.

Formát je co nejjednodušší - na videu je ukázka postupu, v popisu poté anglicky nebo česky (na záladě nastaveného jazyka YouTube) stručný náhled na danou operaci - co se dělá, jakým způsobem, proč je to potřeba a jak to pomůže.

Podívat se na video tipy pro Unreal Engine

Zajímavá fakta

  • S jak velkou mapou / plochou / terénem mohu v Unreal pracovat?

    Téměř jakkoli. Pokud nevěříte, doporučuji shlédnout následující demonstraci - mapu celé planety Země v měřítku 1:1, streamovanou do Unrealu v reálném čase ze serverů ArcGIS prostřednictvím ESRI pluginu pro Unreal.