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 najdokładniejszych i akcji szczegółowych informacji.

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

Profilowanie procesora GPU

Profiler aparatu Unity

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.

Procesor UNITY i procesor GPU

Uwaga

Aby używać profilowania procesora GPU, należy wyłączyć zadania grafiki w ustawieniach odtwarzacza Aparatu Unity. Aby uzyskać więcej informacji, zobacz moduł Profiler użycia procesora GPU aparatu Unity.

Debuger ramki aparatu Unity

Debuger frame debuger aparatu Unity to również zaawansowane i szczegółowe narzędzie do użycia. Dzięki temu będziesz dobrze zapoznać się z tym, co procesor GPU robi każdą ramkę. Warto zwrócić uwagę na dodatkowe elementy docelowe renderowania i polecenia z błędami do kopiowania między nimi, ponieważ są one bardzo kosztowne na urządzeniu HoloLens. W idealnym przypadku nie należy używać obiektów docelowych renderowania poza ekranem na urządzeniu HoloLens. Są one zwykle dodawane podczas włączania kosztownych funkcji renderowania (na przykład MSAA, HDR lub pełnoekranowych efektów, takich jak bloom), których należy unikać.

Nakładka szybkości ramek urządzenia HoloLens

Strona Wydajność systemu portalu urządzeń zawiera dobre podsumowanie wydajności procesora CPU i procesora GPU urządzenia. Możesz włączyć licznik szybkości klatek wyświetlania w zestawie słuchawkowym i wyświetlać wykres szybkości klatek w zestawie słuchawkowym. Te opcje umożliwią odpowiednio licznik i wykres FPS, który zapewni natychmiastową opinię w dowolnej uruchomionej aplikacji na urządzeniu.

Pix

PIX można również używać do profilowania aplikacji aparatu Unity. Istnieją również szczegółowe instrukcje dotyczące używania i instalowania PIX dla HoloLens 2. W kompilacji programistycznej te same zakresy, które są widoczne w debugerze Frame Debugger aparatu Unity, będą również wyświetlane w formacie PIX i można je sprawdzić i profilować bardziej szczegółowo.

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;

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 GetComponent<T>() i Camera.main są droższe w stosunku do 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 GetComponent<T>()
(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 ich zawartość jest kopiowana bezpośrednio 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 związku z tym akceptowalny. Jednak w przypadku funkcji wielokrotnie wywoływanych każdej ramki, a także funkcji przyjmujących duże struktury, jeśli to możliwe, zmodyfikuj definicję funkcji w celu przekazania odwołania. Dowiedz się więcej tutaj

Różne

  1. Fizyki

    a) Ogólnie rzecz biorąc, najprostszym sposobem poprawy fizyki jest ograniczenie ilości czasu poświęcanego na fizykę lub liczbę iteracji na sekundę. Spowoduje to zmniejszenie dokładności symulacji. Zobacz TimeManager w a unity

    b) Typy zderzaczy w a 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ąć zderzaków siatki, które są znacznie droższe niż pierwotne zderzacze.

    Siatka sfero-kapsułowa <<<<< (wypukła) < (niezbieżna)

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

  2. Animacje

    Wyłącz bezczynne animacje, wyłączając składnik Animator (wyłączenie obiektu gry nie będzie miało takiego samego efektu). Unikaj wzorców projektowych, w których animator siedzi w pętli, ustawiając wartość na taką 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 odwrotność kinematyki, znajdowanie ścieżek itp., poszukaj prostszego podejścia lub dostosuj odpowiednie ustawienia pod kątem ich wydajności

Zalecenia dotyczące wydajności procesora CPU na procesor GPU

Ogólnie rzecz biorąc, wydajność procesora CPU do procesora GPU sprowadza się do wywołań rysowania przesył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ż same wywołania rysowania intensywnie korzystają z zasobów, zmniejszenie ich spowoduje zmniejszenie całkowitej wymaganej pracy. 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 ma świetny artykuł, który zawiera omówienie i zagłębia się w przetwarzanie wsadowe wywołań do ich platformy.

Renderowanie z pojedynczym przekazywaniem wystąpienia

Renderowanie z pojedynczym wystąpieniem w a unity umożliwia narysowanie wywołań dla każdego oka, które można zmniejszyć do jednego wystąpienia wywołania rysowania. 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 projekcie aparatu Unity

  1. Otwórz pozycję OpenXR Settings (Edytuj>ustawienia> projektuXR Plugin Management>OpenXR).
  2. Z menu rozwijanego Tryb renderowania wybierz pozycję Pojedyncze wystąpienie z przekazywaniem.

Przeczytaj następujące artykuły z aparatu Unity, aby uzyskać szczegółowe informacje na temat tego podejścia do renderowania.

Uwaga

Jednym z typowych problemów z renderowaniem pojedynczego wystąpienia z przekazywaniem występuje, jeśli deweloperzy mają już istniejące niestandardowe moduły cieniowania, które nie są napisane na potrzeby tworzenia wystąpień. 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 tworzenia wystąpienia.

Zobacz Single Pass Stereo Rendering for HoloLens from Unity (Renderowanie stereo z jednym przekazywaniem dla urządzenia HoloLens z aparatu Unity), aby dowiedzieć się, jak rozwiązać ten problem

Przetwarzanie wsadowe statyczne

Aparat Unity może wsadować wiele obiektów statycznych w celu zmniejszenia liczby wywołań rysowania do procesora GPU. Statyczne przetwarzanie wsadowe działa w przypadku większości obiektów renderujących w a unity, które 1) mają ten sam materiał i 2) są oznaczone jako Statyczne (zaznacz obiekt w a 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 przetwarzanie statyczne może być trudne do wykorzystania na urządzeniu HoloLens, gdzie praktycznie każdy obiekt musi zostać umieszczony, przeniesiony, przeskalowany itp. W przypadku immersyjnych zestawów nagłownych statyczne dzielenie na partie może znacznie zmniejszyć liczbę wywołań rysowania, a tym samym zwiększyć wydajność.

Aby uzyskać więcej informacji, przeczytaj artykuł Static Batching (Przetwarzanie wsadowe statyczne)w obszarze Rysowanie wywołań wsadowych w aferze Unity .

Dynamiczne przetwarzanie wsadowe

Ponieważ problematyczne jest oznaczenie obiektów jako statycznych na potrzeby opracowywania urządzenia HoloLens, dynamiczne dzielenie na partie może być doskonałym narzędziem do zrekompensowania tego braku funkcji. Może być również przydatna w immersywnych zestawach nagłownych. Jednak dynamiczne przetwarzanie wsadowe w a 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.

Aby uzyskać pełną listę, przeczytaj artykuł Dynamic Batching under Draw Call Batching in Unity (Dynamiczne przetwarzanie wsadowe w obszarze Rysuj przetwarzanie wsadowe wywołań w aferze Unity). 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 GameObjects może współdzielić ten sam materiał. Zazwyczaj będzie to blokowane przez potrzebę, aby obiekty GameObject miały unikatową teksturę dla odpowiedniego materiału. Często łączy się tekstury w jedną dużą 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 a aparatu Unity będzie miał skojarzone wywołania rysowania w porównaniu z przesłaniem połączonej siatki w ramach jednego modułu renderowania.

Uwaga

Modyfikowanie właściwości pliku Renderer.material w czasie wykonywania spowoduje utworzenie kopii materiału, co może spowodować przerwanie dzielenia na partie. Użyj obiektu Renderer.sharedMaterial, aby zmodyfikować współużytkowane właściwości materiału w obiektach GameObjects.

Zalecenia dotyczące wydajności procesora GPU

Dowiedz się więcej na temat optymalizowania renderowania grafiki w a 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łnienia.

  • Przepustowość pamięci to szybkość operacji odczytu i zapisu, które procesor GPU może wykonywać z pamięci
    • W afiszcie Unity zmień jakość tekstury w obszarze Edytuj>ustawienia jakościustawień> projektu.
  • Szybkość wypełnienia odnosi się do pikseli, które mogą być rysowane na sekundę przez procesor GPU.

Optymalizowanie udostępniania buforu głębokości

Zalecamy włączenie udostępniania buforu głębokości w celu zoptymalizowania pod kątem stabilności hologramu. Podczas włączania ponownego projektu na podstawie głębokości na późnym etapie przy użyciu tego ustawienia zalecamy wybranie formatu głębokości 16-bitowej zamiast formatu głębokości 24-bitowej . Bufory głębokości 16-bitowej znacząco zmniejszają przepustowość (a tym samym moc) skojarzoną z ruchem buforu głębokości. Może to być duża poprawa zarówno w zakresie redukcji mocy, jak i wydajności. Istnieją jednak dwa możliwe negatywne wyniki przy użyciu formatu głębokości 16-bitowej.

Walka Z

Zmniejszona wierność zakresu głębokości sprawia, że walka z jest bardziej prawdopodobna w przypadku 16 bitów niż 24-bitowa. Aby uniknąć tych artefaktów, zmodyfikuj bliskie/dalekie płaszczyzny klipów aparatu Unity , aby uwzględnić niższą precyzję. W przypadku aplikacji opartych na urządzeniu HoloLens daleko wycinek o wysokości 50 m zamiast domyślnego aparatu Unity 1000 m może na ogół wyeliminować każdą walkę z.

Wyłączony bufor wzornika

Gdy aparat Unity tworzy teksturę renderowania z głębokością 16-bitową, nie utworzono buforu wzornika. Wybranie formatu głębokości 24-bitowej, zgodnie z opisem w dokumentacji aparatu Unity, spowoduje utworzenie 24-bitowego bufora z i 8-bitowego buforu wzornika (jeśli 32-bitowy ma zastosowanie na urządzeniu (na przykład holoLens), co zwykle ma zastosowanie).

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 aliasowanie, kwitnie i nie tylko.

Optymalne ustawienia oświetlenia

Globalne oświetlenie w czasie rzeczywistym w aferze Unity może zapewnić doskonałe 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ąopcji Ustawienia> oświetleniarenderowania> okien > Usuń zaznaczenie globalnego oświetlenia w czasie rzeczywistym.

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

Edytuj>Ustawienia projektu, 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"

    Wybieranie cieniowania w środowisku Unity

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

    Kompilowanie kodu cieniowania w środowisku 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)

    Operacje cieniowania standardowego aparatu Unity

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, ta liczba podwoi się, ponieważ istnieją dwa ekrany. Jeśli aplikacja rzeczywistości mieszanej ma wiele przebiegów, pełnoekranowych efektów przetwarzania końcowego lub renderowania wielu siatk do tego samego piksela, ta liczba znacznie wzrośnie.

W związku z tym zmniejszenie liczby operacji w cieniowaniu fragmentów może na ogół dać znacznie większe zyski wydajności w przypadku optymalizacji w cieniowaniu wierzchołka.

Alternatywy cieniowania w warstwie Standardowa aparatu Unity

Zamiast używać fizycznie opartego renderowania (PBR) lub innego wysokiej jakości cieniowania, przyjrzyj się wykorzystaniu bardziej wydajnego i tańszego cieniowania. Zestaw narzędzi Mixed Reality udostępniastandardowy moduł cieniowania mrTK zoptymalizowany pod kątem projektów rzeczywistości mieszanej.

Aparat Unity zapewnia również nielitowane, oświetlone wierzchołki, rozproszone i inne uproszczone opcje cieniowania, które są szybsze w porównaniu do cieniowania w warstwie Standardowa 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 sztuczek, aby zoptymalizować czas ładowania cieniowania. W szczególności wstępne ładowanie cieniowania oznacza, że nie będą widoczne żadne trafienia z powodu kompilacji cieniowania środowiska uruchomieniowego.

Limit overdraw (Limit overdraw)

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

Ogólnie rzecz biorąc, przerysowanie można ograniczyć przez przedsuwanie 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 operacje alokacji pamięci & mogą mieć negatywny wpływ na aplikację holograficzne, 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śmieceń pamięci.

Wyrzucanie elementów bezużytecznych

Aplikacje holograficzne utracą czas przetwarzania zasobów obliczeniowych do modułu odśmiecenia pamięci (GC), gdy GC jest aktywowana w celu analizowania obiektów, które nie są już w zakresie podczas wykonywania, a ich pamięć musi zostać zwolniona, dzięki czemu można ją udostępnić do ponownego użycia. Stałe alokacje i delokacje zwykle wymagają, aby moduł odśmiecania pamięci był uruchamiany częściej, co oznacza szkodę w wydajności i środowisku użytkownika.

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

Jedną z najczęstszych 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. Wszelkie odwołania powinny być przechwytywane podczas uruchamiania() lub Awake() i ponownie używane w nowszych 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 do aplikacji Debug.Log(), gdy nie są już potrzebne, ponieważ są one nadal wykonywane we wszystkich wersjach kompilacji aplikacji
  • Jeśli aplikacja holograficzne zwykle wymaga dużej ilości pamięci, rozważ wywołanie elementu System.GC.Collect() podczas fazy ładowania, na przykład 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 alokacji obiektów. 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 być zacięta lub hitch. 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 ekran powitalny holographic zostanie wyświetlony użytkownikowi.

Zobacz też