Zalecenia dotyczące wydajności aparatu Unity

Ten artykuł opiera się na zaleceniach dotyczących wydajności rzeczywistości mieszanej, ale koncentruje się na ulepszeniach specyficznych dla aparatu Unity.

Niedawno opublikowaliśmy aplikację o nazwie Podstawy jakości, która obejmuje typowe problemy z wydajnością, projektowaniem i środowiskiem oraz rozwiązaniami HoloLens 2 aplikacji. Ta aplikacja jest doskonałym pokazem wizualnym zawartości, która jest poniżej.

Najważniejszym pierwszym krokiem podczas optymalizacji wydajności aplikacji rzeczywistości mieszanej w środowisku Unity jest upewnienie się, że używasz zalecanych ustawień środowiska dla aparatu Unity. Ten artykuł zawiera zawartość z niektórymi z najważniejszych konfiguracji scen do tworzenia wydajnych aplikacji Mixed Reality. Niektóre z tych zalecanych ustawień są również wyróżnione poniżej.

Jak profilować za pomocą aparatu Unity

Aparat Unity udostępnia wbudowany program Unity Profiler , który jest doskonałym zasobem do zbierania cennych szczegółowych informacji o wydajności dla określonej aplikacji. Chociaż można uruchomić profilera w edytorze, te metryki nie reprezentują prawdziwego środowiska uruchomieniowego, dlatego wyniki powinny być używane ostrożnie. Zalecamy zdalne profilowanie aplikacji podczas uruchamiania na urządzeniu w celu uzyskania najbardziej dokładnych i akcji szczegółowych informacji. Ponadto debuger Frame Debugger aparatu Unity jest również zaawansowanym narzędziem do analizy i do użycia.

Uwaga

Aparat Unity umożliwia łatwe modyfikowanie rozdzielczości docelowej renderowania aplikacji w czasie wykonywania za pomocą właściwości XRSettings.renderViewportScale . Końcowy obraz przedstawiony na urządzeniu ma stałą rozdzielczość. Platforma będzie próbkować dane wyjściowe o niższej rozdzielczości, aby utworzyć obraz o wyższej rozdzielczości do renderowania na ekranach.

UnityEngine.XR.XRSettings.renderViewportScale = 0.7f;

Aparat Unity udostępnia świetną dokumentację dla następujących celów:

  1. Jak zdalnie połączyć profilera aparatu Unity z aplikacjami platformy UWP
  2. Jak skutecznie diagnozować problemy z wydajnością w programie Unity Profiler

Uwaga

Po połączeniu profilera aparatu Unity i po dodaniu profilera procesora GPU (zobacz Dodawanie profilera w prawym górnym rogu), można zobaczyć, ile czasu poświęca się odpowiednio na procesor GPU procesora CPU & w środku profilera. Dzięki temu deweloper może uzyskać szybkie przybliżenie, jeśli ich aplikacja jest powiązana z procesorem CPU lub procesorem GPU.

Unity CPU vs GPU

Zalecenia dotyczące wydajności procesora CPU

Poniższa zawartość obejmuje bardziej szczegółowe rozwiązania dotyczące wydajności, szczególnie przeznaczone do programowania w języku Unity & w języku C#.

Odwołania do pamięci podręcznej

Zalecamy buforowanie odwołań do wszystkich odpowiednich składników i obiektów GameObject podczas inicjowania, ponieważ powtarzające się wywołania funkcji, takie jak GetComponentT<>() i Camera.main są droższe względem kosztu pamięci do przechowywania wskaźnika. . Camera.main po prostu używa funkcji FindGameObjectsWithTag() poniżej, która kosztownie wyszukuje wykres sceny dla obiektu aparatu z tagiem "MainCamera".

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    private Camera cam;
    private CustomComponent comp;

    void Start() 
    {
        cam = Camera.main;
        comp = GetComponent<CustomComponent>();
    }

    void Update()
    {
        // Good
        this.transform.position = cam.transform.position + cam.transform.forward * 10.0f;

        // Bad
        this.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 10.0f;

        // Good
        comp.DoSomethingAwesome();

        // Bad
        GetComponent<CustomComponent>().DoSomethingAwesome();
    }
}

Uwaga

Unikaj polecenia GetComponent(string)
W przypadku korzystania z polecenia GetComponent()istnieje kilka różnych przeciążeń. Ważne jest, aby zawsze używać implementacji opartych na typach i nigdy nie przeciążenia wyszukiwania opartego na ciągach. Wyszukiwanie według ciągu w scenie jest znacznie droższe niż wyszukiwanie według typu.
(Dobry) Składnik GetComponent(typ)
(Dobry) T GetComponentT<>()
(Zły) Składnik GetComponent(ciąg)>

Unikaj kosztownych operacji

  1. Unikaj używania LINQ

    Mimo że LINQ może być czysty i łatwy do odczytania i zapisu, zwykle wymaga więcej obliczeń i pamięci niż w przypadku ręcznego pisania algorytmu.

    // Example Code
    using System.Linq;
    
    List<int> data = new List<int>();
    data.Any(x => x > 10);
    
    var result = from x in data
                 where x > 10
                 select x;
    
  2. Typowe interfejsy API aparatu Unity

    Niektóre interfejsy API aparatu Unity, choć przydatne, mogą być kosztowne do wykonania. Większość z nich obejmuje przeszukiwanie całego grafu sceny w celu znalezienia odpowiedniej listy obiektów GameObjects. Te operacje można zwykle uniknąć, buforując odwołania lub implementując składnik menedżera dla obiektów GameObjects w celu śledzenia odwołań w czasie wykonywania.

        GameObject.SendMessage()
        GameObject.BroadcastMessage()
        UnityEngine.Object.Find()
        UnityEngine.Object.FindWithTag()
        UnityEngine.Object.FindObjectOfType()
        UnityEngine.Object.FindObjectsOfType()
        UnityEngine.Object.FindGameObjectsWithTag()
        UnityEngine.Object.FindGameObjectsWithTag()
    

Uwaga

Funkcja SendMessage() i BroadcastMessage() powinna zostać wyeliminowana ze wszystkich kosztów. Te funkcje mogą być w kolejności 1000x wolniejsze niż wywołania funkcji bezpośrednich.

  1. Uważaj na boks

    Boxing to podstawowa koncepcja języka C# i środowiska uruchomieniowego. Jest to proces zawijania zmiennych typowych wartości, takich jak char, int, boolitp. do zmiennych typowych odwołań. Gdy zmienna typu wartości jest "boxed", jest opakowana w element , który jest przechowywany na zarządzanym System.Objectstercie. Pamięć jest przydzielana i ostatecznie po usunięciu musi zostać przetworzona przez moduł odśmiecający pamięć. Te alokacje i przydziały powodują koszt wydajności, a w wielu scenariuszach są niepotrzebne lub można je łatwo zamienić na mniej kosztowną alternatywę.

    Aby uniknąć boxingu, upewnij się, że zmienne, pola i właściwości, w których są przechowywane typy liczbowe i struktury (w tym Nullable<T>) są silnie typizowane jako określone typy, takie jak int, float? lub MyStruct, zamiast używać obiektu. W przypadku umieszczania tych obiektów na liście należy użyć silnie typizowanej listy, takiej jak List<int> zamiast List<object> lub ArrayList.

    Przykład boksu w języku C #

    // boolean value type is boxed into object boxedMyVar on the heap
    bool myVar = true;
    object boxedMyVar = myVar;
    

Powtarzanie ścieżek kodu

Wszystkie powtarzające się funkcje wywołania zwrotnego aparatu Unity (tj. Aktualizacja), które są wykonywane wiele razy na sekundę i/lub ramkę, powinny być starannie napisane. Wszelkie kosztowne operacje w tym miejscu będą miały ogromny i spójny wpływ na wydajność.

  1. Puste funkcje wywołania zwrotnego

    Chociaż poniższy kod może wydawać się niewinny, aby pozostawić w aplikacji, zwłaszcza że każdy skrypt aparatu Unity automatycznie inicjuje metodę Update, te puste wywołania zwrotne mogą stać się kosztowne. Aparat Unity działa tam i z powrotem między granicą kodu niezarządzanego i zarządzanego między kodem Aparatu UnityEngine i kodem aplikacji. Przełączanie kontekstu przez ten most jest dość kosztowne, nawet jeśli nie ma nic do wykonania. Staje się to szczególnie problematyczne, jeśli aplikacja ma 100 obiektów GameObject z składnikami, które mają puste powtarzające się wywołania zwrotne aparatu Unity.

    void Update()
    {
    }
    

Uwaga

Update() jest najczęstszym przejawem tego problemu z wydajnością, ale inne powtarzające się wywołania zwrotne aparatu Unity, takie jak następujące, mogą być równie złe, jeśli nie są gorsze: FixedUpdate(), LateUpdate(), OnPostRender", OnPreRender(), OnRenderImage(), itp.

  1. Operacje do faworyzowania uruchamiania raz na ramkę

    Następujące interfejsy API aparatu Unity są typowymi operacjami dla wielu aplikacji Holographic Apps. Chociaż nie zawsze jest to możliwe, wyniki z tych funkcji można często obliczać raz i wyniki ponownie wykorzystywane w całej aplikacji dla danej ramki.

    a) Dobrym rozwiązaniem jest posiadanie dedykowanej klasy lub usługi Singleton do obsługi spojrzenia Raycast w scenie, a następnie ponowne użycie tego wyniku we wszystkich innych składnikach sceny, zamiast powtarzania i identycznych operacji Raycast przez każdy składnik. Niektóre aplikacje mogą wymagać raycasts z różnych źródeł lub różnych mask warstw.

        UnityEngine.Physics.Raycast()
        UnityEngine.Physics.RaycastAll()
    

    b) Unikaj operacji GetComponent() w powtarzających się wywołaniach zwrotnych aparatu Unity, takich jak Update(), buforując odwołania do start () lub Awake()

        UnityEngine.Object.GetComponent()
    

    c) Dobrym rozwiązaniem jest utworzenie wystąpienia wszystkich obiektów, jeśli to możliwe, podczas inicjowania i używania puli obiektów do recyklingu i ponownego używania obiektów GameObjects w całym środowisku uruchomieniowym aplikacji

        UnityEngine.Object.Instantiate()
    
  2. Unikaj interfejsów i konstrukcji wirtualnych

    Wywoływanie wywołań funkcji za pośrednictwem interfejsów i obiektów bezpośrednich lub wywoływanie funkcji wirtualnych często jest znacznie droższe niż przy użyciu konstrukcji bezpośrednich lub wywołań funkcji bezpośrednich. Jeśli funkcja wirtualna lub interfejs są niepotrzebne, należy ją usunąć. Jednak osiągnięcie wydajności tych podejść jest warte kompromisu, jeśli ich użycie upraszcza współpracę deweloperów, czytelność kodu i możliwość utrzymania kodu.

    Ogólnie rzecz biorąc, zaleceniem jest nie oznaczanie pól i funkcji jako wirtualnych, chyba że istnieje jasne oczekiwanie, że ten element członkowski musi zostać zastąpiony. Należy zachować szczególną ostrożność w przypadku ścieżek kodu o wysokiej częstotliwości, które są wywoływane wiele razy na ramkę, a nawet raz na ramkę UpdateUI() , taką jak metoda.

  3. Unikaj przekazywania struktur według wartości

    W przeciwieństwie do klas struktury są typami wartości, a po przekazaniu bezpośrednio do funkcji ich zawartość jest kopiowana do nowo utworzonego wystąpienia. Ta kopia dodaje koszt procesora CPU, a także dodatkową pamięć na stosie. W przypadku małych struktur efekt jest minimalny i w ten sposób akceptowalny. Jednak w przypadku funkcji wielokrotnie wywoływanych każdej ramki, a także funkcji, które przyjmują duże struktury, jeśli to możliwe, zmodyfikuj definicję funkcji, aby przejść przez odwołanie. Dowiedz się więcej tutaj

Różne

  1. Fizyki

    a) Ogólnie najprostszym sposobem poprawy fizyki jest ograniczenie ilości czasu spędzonego na fizyce lub liczbę iteracji na sekundę. Spowoduje to zmniejszenie dokładności symulacji. Zobacz TimeManager w środowisku Unity

    b) Typy zderzaków w unity mają znacznie różne cechy wydajności. Poniższa kolejność zawiera listę najbardziej wydajnych zderzaków do najmniej wydajnych zderzaków od lewej do prawej. Ważne jest, aby uniknąć Mesh zderzaków, które są znacznie droższe niż pierwotne zderzacze.

    Mesh Mesh skrzynki Mesh kapsułowej <<<< sfery < (niezbiełkowe) <

    Aby uzyskać więcej informacji, zobacz Artykuł Unity Physics Best Practices (Najlepsze rozwiązania dotyczące fizyki aparatu Unity )

  2. Animacje

    Wyłącz animacje bezczynności, wyłączając składnik Animator (wyłączenie obiektu gry nie będzie miało tego samego efektu). Unikaj wzorców projektowania, w których animacja siedzi w pętli ustawiając wartość na tę samą rzecz. Istnieje znaczne obciążenie dla tej techniki, bez wpływu na aplikację. Więcej informacji można znaleźć tutaj.

  3. Złożone algorytmy

    Jeśli aplikacja używa złożonych algorytmów, takich jak odwrotne kinematyka, znajdowanie ścieżki itp., poszukaj prostszego podejścia lub dostosuj odpowiednie ustawienia pod kątem ich wydajności

Zalecenia dotyczące wydajności procesora CPU do procesora GPU

Ogólnie rzecz biorąc, wydajność procesora CPU do procesora GPU sprowadza się do wywołań rysowania przesłanych do karty graficznej. Aby poprawić wydajność, wywołania rysowania muszą być strategicznie a) zmniejszone lub b) zrestrukturyzowane w celu uzyskania optymalnych wyników. Ponieważ wywołania rysowania są intensywnie obciążające zasoby, zmniejszenie liczby wywołań zmniejszy ogólną wymaganą pracę. Ponadto zmiany stanu między wywołaniami rysowania wymagają kosztownej weryfikacji i kroków tłumaczenia w sterowniku graficznym, a tym samym restrukturyzacja wywołań rysowania aplikacji w celu ograniczenia zmian stanu (np. różnych materiałów itp.) może zwiększyć wydajność.

Aparat Unity zawiera świetny artykuł, który zawiera omówienie i szczegółowe informacje na temat przetwarzania wsadowego wywołań rysowania dla ich platformy.

Renderowanie pojedynczego wystąpienia

Renderowanie pojedynczego wystąpienia w środowisku Unity umożliwia narysowanie wywołań dla każdego oka, które można zmniejszyć do jednego wystąpienia wywołania losowania. Ze względu na współistnienie pamięci podręcznej między dwoma wywołaniami rysowania, istnieje również pewne zwiększenie wydajności procesora GPU.

Aby włączyć tę funkcję w Project aparatu Unity

  1. Otwórz Ustawienia XR odtwarzacza (przejdź do pozycji Edytuj>Project Ustawienia>PlayerXR> Ustawienia)
  2. Wybierz pozycję Pojedyncze wystąpienie z menu rozwijanego Metoda renderowania stereo (pole wyboru Obsługiwana rzeczywistość wirtualna musi być zaznaczone)

Zapoznaj się z następującymi artykułami z aparatu Unity, aby uzyskać szczegółowe informacje na temat tego podejścia renderowania.

Uwaga

Jednym z typowych problemów z renderowaniem pojedynczego wystąpienia z przekazywaniem występuje, jeśli deweloperzy mają już istniejące niestandardowe cieniowania, które nie są napisane na potrzeby stancingu. Po włączeniu tej funkcji deweloperzy mogą zauważyć, że niektóre obiekty GameObject są renderowane tylko w jednym oku. Jest to spowodowane tym, że skojarzone niestandardowe cieniowania nie mają odpowiednich właściwości do ściągnięcia.

Aby rozwiązać ten problem, zobacz Renderowanie jednoprzepustowe stereo dla HoloLens z aparatu Unity

Statyczne przetwarzanie wsadowe

Aparat Unity może wsadować wiele obiektów statycznych, aby zmniejszyć liczbę wywołań rysowania do procesora GPU. Statyczne przetwarzanie wsadowe działa w przypadku większości obiektów renderujących w środowisku Unity, które 1) mają ten sam materiał i 2) są oznaczone jako Statyczne (wybierz obiekt w środowisku Unity i zaznacz pole wyboru w prawym górnym rogu inspektora). Obiekty GameObject oznaczone jako Statyczne nie mogą być przenoszone w całym środowisku uruchomieniowym aplikacji. W związku z tym statyczne przetwarzanie wsadowe może być trudne do wykorzystania w HoloLens, gdzie praktycznie każdy obiekt musi zostać umieszczony, przeniesiony, skalowany itp. W przypadku immersyjnych zestawów słuchawkowych statyczne partie mogą znacznie zmniejszyć liczbę wywołań rysowania, a tym samym zwiększyć wydajność.

Aby uzyskać więcej informacji, przeczytaj artykuł Static Batching under Draw Call Batching in Unity (Przetwarzanie wsadowe statyczne w usłudze Draw Call Batching in Unity).

Dynamiczne przetwarzanie wsadowe

Ponieważ problematyczne jest oznaczanie obiektów jako statycznych na potrzeby programowania HoloLens, dynamiczne przetwarzanie wsadowe może być doskonałym narzędziem do zrekompensowania tego braku funkcji. Może to być również przydatne w immersyjnych zestawach słuchawkowych, jak również. Jednak dynamiczne przetwarzanie wsadowe w środowisku Unity może być trudne, ponieważ obiekty GameObjects muszą a) współdzielić ten sam materiał i b) spełniają długą listę innych kryteriów.

Przeczytaj artykuł Dynamic Batching under Draw Call Batching in Unity (Dynamiczne przetwarzanie wsadowe w usłudze Draw Call Batching w środowisku Unity), aby uzyskać pełną listę. Najczęściej obiekty GameObject są nieprawidłowe do dynamicznego dzielenia na partie, ponieważ skojarzone dane siatki nie mogą przekraczać 300 wierzchołków.

Inne techniki

Przetwarzanie wsadowe może wystąpić tylko wtedy, gdy wiele obiektów GameObject może współużytkować ten sam materiał. Zazwyczaj będzie to blokowane przez potrzebę, aby obiekty GameObject miały unikatową teksturę dla odpowiedniego materiału. Często łączy tekstury w jedną wielką teksturę, czyli metodę znaną jako Texture Atlasing.

Ponadto lepiej jest połączyć siatki w jeden obiekt GameObject, jeśli jest to możliwe i uzasadnione. Każdy moduł renderowania w środowisku Unity będzie miał skojarzone wywołania rysowania w porównaniu do przesyłania połączonej siatki w ramach jednego modułu renderowanego.

Uwaga

Modyfikowanie właściwości pliku Renderer.material w czasie wykonywania spowoduje utworzenie kopii materiału i potencjalnie przerwanie przetwarzania wsadowego. Użyj elementu Renderer.sharedMaterial, aby zmodyfikować właściwości udostępnionego materiału w obiektach GameObjects.

Zalecenia dotyczące wydajności procesora GPU

Dowiedz się więcej na temat optymalizowania renderowania grafiki w środowisku Unity

Przepustowość i współczynniki wypełnienia

Podczas renderowania ramki na procesorze GPU aplikacja jest powiązana z przepustowością pamięci lub szybkością wypełniania.

  • Przepustowość pamięci to szybkość odczytów i zapisów, które procesor GPU może wykonywać z pamięci
    • W środowisku Unity zmień jakość tekstury w pozycji Edytuj>Project Ustawienia>Quality Ustawienia.
  • Szybkość wypełniania odnosi się do pikseli, które mogą być rysowane na sekundę przez procesor GPU.

Optymalizowanie udostępniania buforu głębokości

Zaleca się włączenie udostępniania buforu głębokości w obszarze Odtwarzacz XR Ustawienia w celu zoptymalizowania pod kątem stabilności hologramu. Podczas włączania ponownego projektu opartego na głębi na późnym etapie przy użyciu tego ustawienia zaleca się jednak wybranie formatu głębokości 16-bitowej zamiast formatu głębokości24-bitowej. Bufory głębokości 16-bitowej znacznie zmniejszają przepustowość (a tym samym moc) skojarzoną z ruchem buforowym głębokości. Może to być duża wygrana zarówno w zakresie redukcji mocy, jak i poprawy wydajności. Istnieją jednak dwa możliwe negatywne wyniki przy użyciu formatu głębokości 16-bitowej.

Walka Z

Zmniejszona dokładność zakresu głębokości sprawia, że walka z prawdopodobnie wystąpi z 16 bitami niż 24-bitowa. Aby uniknąć tych artefaktów, zmodyfikuj bliskie/dalekie płaszczyzny aparatu Unity , aby uwzględnić niższą precyzję. W przypadku aplikacji opartych na HoloLens dalekoskładnikowy o wartości 50 m zamiast domyślnego aparatu Unity 1000 m może ogólnie wyeliminować wszelkie walki z.

Wyłączony bufor wzornika

Gdy środowisko Unity tworzy teksturę renderowania z 16-bitową głębokością, nie utworzono buforu wzornika. Wybranie formatu głębokości 24-bitowej dla dokumentacji aparatu Unity spowoduje utworzenie 24-bitowego buforu z, a także [8-bitowego buforu wzornika] () (https://docs.unity3d.com/Manual/SL-Stencil.htmljeśli 32-bitowy ma zastosowanie na urządzeniu, co jest ogólnie takie jak HoloLens).

Unikaj efektów pełnoekranowych

Techniki działające na pełnym ekranie mogą być kosztowne, ponieważ ich kolejność wielkości to miliony operacji na każdej ramce. Zaleca się unikanie efektów przetwarzania końcowego , takich jak anty aliasing, bloom i nie tylko.

Optymalne ustawienia oświetlenia

Globalne oświetlenie w środowisku Unity w czasie rzeczywistym może zapewnić wybitne wyniki wizualne, ale obejmuje kosztowne obliczenia oświetlenia. Zalecamy wyłączenie globalnego oświetlenia w czasie rzeczywistym dla każdego pliku sceny aparatu Unity za pomocą poleceniaWindowRenderingLighting>>Ustawienia> Usuń zaznaczenie globalnego oświetlenia w czasie rzeczywistym.

Ponadto zaleca się wyłączenie całego rzutowania w tle, ponieważ dodanie kosztownego procesora GPU przechodzi do sceny aparatu Unity. Cienie można wyłączyć na światło, ale można również sterować całościowo za pomocą ustawień jakości.

Edytuj>Project Ustawienia, a następnie wybierz kategorię >Jakość Wybierz niską jakość dla platformy uwP. Można również ustawić właściwość Cienie na Wartość Wyłącz cienie.

Zalecamy używanie oświetlenia pieczonego z modelami w środowisku Unity.

Zmniejsz liczbę poli

Liczba wielokątów jest zmniejszana przez jedną z tych

  1. Usuwanie obiektów ze sceny
  2. Decymacja zasobów, która zmniejsza liczbę wielokątów dla danej siatki
  3. Implementowanie systemu poziomów szczegółów (LOD) w aplikacji, która renderuje daleko idące obiekty z niższą wersją wielokąta tej samej geometrii

Omówienie cieniowania w środowisku Unity

Łatwe przybliżenie do porównywania cieniowania w wydajności polega na zidentyfikowaniu średniej liczby operacji wykonywanych w czasie wykonywania. Można to łatwo zrobić w środowisku Unity.

  1. Wybierz zasób cieniowania lub wybierz materiał, a następnie w prawym górnym rogu okna inspektora wybierz ikonę koła zębatego, a następnie pozycję "Wybierz cieniator"

    Select shader in Unity

  2. Po wybraniu elementu zawartości cieniowania wybierz przycisk "Kompiluj i pokaż kod" w oknie inspektora

    Compile Shader Code in Unity

  3. Po zakończeniu kompilowania wyszukaj sekcję statystyk w wynikach z liczbą różnych operacji zarówno dla cieniowania wierzchołków, jak i cieniowania pikseli (Uwaga: cieniowanie pikseli jest często nazywane cieniowaniem fragmentów)

    Unity Standard Shader Operations

Optymalizowanie cieniowania pikseli

Patrząc na skompilowane wyniki statystyki przy użyciu powyższej metody, cieniowanie fragmentów będzie zwykle wykonywać więcej operacji niż cieniowanie wierzchołków, średnio. Cieniowanie fragmentów, znane również jako cieniowanie pikseli, jest wykonywane na piksel w danych wyjściowych ekranu, podczas gdy cieniowanie wierzchołka jest wykonywane tylko na wierzchołku wszystkich siatk rysowanych na ekranie.

W związku z tym nie tylko cieniowania fragmentów mają więcej instrukcji niż cieniowania wierzchołków ze względu na wszystkie obliczenia oświetlenia, cieniowanie fragmentów jest prawie zawsze wykonywane na większym zestawie danych. Jeśli na przykład dane wyjściowe ekranu są obrazem 2k na 2k, cieniowanie fragmentów może zostać wykonane 2000*2000 = 4000 000 razy. Jeśli renderowanie dwóch oczu, liczba ta podwaja się, ponieważ istnieją dwa ekrany. Jeśli aplikacja rzeczywistości mieszanej ma wiele przebiegów, efektów przetwarzania końcowego pełnoekranowego lub renderowania wielu siatki w tym samym pikselu, ta liczba znacznie wzrośnie.

W związku z tym zmniejszenie liczby operacji w cieniowaniu fragmentów może zwykle dać znacznie większy wzrost wydajności w optymalizacji w cieniowaniu wierzchołka.

Alternatywy cieniowania standardowego aparatu Unity

Zamiast korzystać z renderowania fizycznego (PBR) lub innego cieniowania wysokiej jakości, przyjrzyj się użyciu bardziej wydajnego i tańszego cieniowania. Zestaw narzędzi Mixed Reality udostępnia standardowy moduł cieniowania zestawu narzędzi MRTK zoptymalizowany pod kątem projektów rzeczywistości mieszanej.

Aparat Unity zapewnia również nielitowe, oświetlone wierzchołki, rozproszone i inne uproszczone opcje cieniowania, które są szybsze w porównaniu do cieniowania standardowego aparatu Unity. Aby uzyskać bardziej szczegółowe informacje, zobacz Użycie i wydajność wbudowanych cieniowania .

Wstępne ładowanie cieniowania

Użyj wstępnego ładowania cieniowania i innych wskazówek, aby zoptymalizować czas ładowania cieniowania. W szczególności wstępne ładowanie cieniowania oznacza, że nie zobaczysz żadnych trafień ze względu na kompilację cieniowania środowiska uruchomieniowego.

Limit przerysowania

W amencie Unity można wyświetlić przerysowanie sceny, przełączając menu trybu rysowania w lewym górnym rogu widoku Scena i wybierając pozycję Przerysuj.

Ogólnie rzecz biorąc, przerysowanie może być ograniczane przez wyłusanie obiektów przed wysłaniem ich do procesora GPU. Aparat Unity zawiera szczegółowe informacje na temat implementowania aparatu Occlusion Culling .

Zalecenia dotyczące pamięci

Nadmierne przydzielanie & pamięci operacji cofania alokacji może mieć negatywny wpływ na aplikację holograficzną, co powoduje niespójną wydajność, zamrożone ramki i inne szkodliwe zachowanie. Szczególnie ważne jest, aby zrozumieć zagadnienia dotyczące pamięci podczas opracowywania w środowisku Unity, ponieważ zarządzanie pamięcią jest kontrolowane przez moduł odśmiecający pamięci.

Wyrzucanie elementów bezużytecznych

Aplikacje holograficzne utracą czas przetwarzania zasobów obliczeniowych do modułu odśmiecanie pamięci (GC), gdy GC zostanie aktywowany w celu analizowania obiektów, które nie są już objęte zakresem podczas wykonywania, a ich pamięć musi zostać zwolniona, dzięki czemu będzie można ją udostępnić do ponownego użycia. Stałe alokacje i delokacje zwykle wymagają częstszego uruchamiania modułu odśmiecania pamięci, co szkodzi wydajności i środowisku użytkownika.

Aparat Unity udostępnia doskonałą stronę, która szczegółowo wyjaśnia, jak działa moduł odśmieczania pamięci, oraz wskazówki dotyczące pisania bardziej wydajnego kodu w odniesieniu do zarządzania pamięcią.

Jedną z najbardziej typowych rozwiązań, które prowadzą do nadmiernego odzyskiwania pamięci, nie jest buforowanie odwołań do składników i klas w programowaniu aparatu Unity. Wszystkie odwołania powinny być przechwytywane podczas uruchamiania() lub funkcji Awake() i ponownie używane w późniejszych funkcjach, takich jak Update() lub LateUpdate().

Inne szybkie porady:

  • Używanie klasy StringBuilder C# do dynamicznego kompilowania złożonych ciągów w czasie wykonywania
  • Usuń wywołania funkcji Debug.Log(), gdy nie są już potrzebne, ponieważ nadal są wykonywane we wszystkich wersjach kompilacji aplikacji
  • Jeśli aplikacja holograficzna zwykle wymaga dużej ilości pamięci, rozważ wywołanie metody System.GC.Collect() podczas faz ładowania, takich jak podczas prezentowania ekranu ładowania lub przejścia

Buforowanie obiektów

Buforowanie obiektów to popularna technika zmniejszania kosztów ciągłej alokacji obiektów i cofania alokacji. Odbywa się to przez przydzielanie dużej puli identycznych obiektów i ponowne użycie nieaktywnych, dostępnych wystąpień z tej puli zamiast stale duplikować i niszczyć obiekty w czasie. Pule obiektów doskonale nadają się do ponownego użycia składników, które mają zmienny okres istnienia w aplikacji.

Wydajność uruchamiania

Rozważ uruchomienie aplikacji z mniejszą sceną, a następnie załadowanie pozostałej części sceny za pomocą narzędzia SceneManager.LoadSceneAsync . Dzięki temu aplikacja może jak najszybciej przejść do stanu interaktywnego. Może wystąpić duży wzrost użycia procesora CPU podczas aktywowania nowej sceny i że każda renderowana zawartość może się zacinać lub uderzać. Jednym ze sposobów obejścia tego problemu jest ustawienie właściwości AsyncOperation.allowSceneActivation na wartość "false" na ładowanej scenie, poczekaj na załadowanie sceny, wyczyść ekran na czarny, a następnie ustaw ją z powrotem na "true", aby ukończyć aktywację sceny.

Pamiętaj, że podczas ładowania sceny uruchamiania do użytkownika zostanie wyświetlony ekran powitalny holograficzny.

Zobacz też