Optimierung in UE - wie bekomme ich mehr FPS

  • Optimierung ist wieder mal so ein Thema zu dem ich ein ganzes Buch schreiben könnte - aber wie immer belasse ich es mal mit ein paar Tips und Denkanstössen. Von daher mal locker flockig runtergeschrieben was man sich so überlegen sollte wenn man merkt das Spiel läuft etwas zu lahm.


    1. Zielplattform definieren.

    Wenn ihr ein Puzzlespiel für Android oder IOS (iPhone) Plattformen macht dann sollte das nach Möglichkeit auf jeder noch so alten Gurke laufen. Klar euer iPhone 11 oder Samsung Galaxy Note 9 sind hip aber schaut mal wie viele Leute noch mit einem iPhone 6 rumlaufen. Unterstützt ihr mehr Modelle habt ihr mehr potentielle Käufer. End of Story. Macht ihr dagegen ein VR Spiel für HTC Vive und co dann braucht ihr realistisch nicht damit rechnen daß jemand unter ner Geforce GTX 970 sowas überhaupt probiert zu starten. Von daher macht euch erst mal realistisch Gedanken was die Mindestanforderungen sind und wieviel FPS ihr für das Minimum Rig bieten wollt. Beim PC hat man den Luxus man kann die Auflösung und Scalability settings runterdrehen kann - dann läuft es auf einmal auf ner Steinzeit Grafikkarte wie ner Geforce GT 540 einwandfrei - sieht aber bescheiden aus. Eure überlegungen sollten also schon voraussetzen was die Mindestanforderung für "epic" scalability ist (Ihr kennt "Epic" als beste Einstellung im Editor).


    2. Echte Tests.

    Klar wenn es im Editor gut läuft läuft es kompiliert in der regel noch besser. Aber unabdingbar ist messen statt schätzen. "Stat FPS" und "Stat unit" sind klassische Konsolenbefehle mit denen ihr FPS/Leistung objektiv messen könnt. Kann man mit nem console command node auch auf nen key legen oder automatisch starten. Latscht mal durch eure levels und schaut auf die FPS. Wenn ihr durrchgehend 60 fps wollt ist es unbedenklich wenn die in der kompilierten version auf der Minimum Hardware mal auf 58 droppen, aber wenn ihr mal auf 5 fps kommt müsst ihr euch schon was überlegen.


    3. Echtes Optimieren

    Ja klar - die FPS reichen nicht - das ganze läuft wie ein Sack Muscheln auf meiner Ziel-Hardware, ich muss optimieren. Wichtig ist es erst mal rauszufinden was das ganze so lahm macht. Was kostet viel GPU/CPU/Memory und wo ziehe ich die Schrauben an. Mal ganz dumm gesprochen - wenn das Problem an euren game ist daß ihr im level BP Tick jedes Frame die Zahl Pi auf 100 Stellen hinter dem Komma ausrechnet nützt es euch nix an den 3D Modellen oder Texturen zu schrauben. Von daher ist es gut in etwa zu wissen was die meiste Performance zieht. Dazu kommen wir in den nächsten Abschnitten.


    4. UE4 Profiler

    Ganz gemein daß ich dieses Unwort hier raushaue. Die meisten Hobby Programmierer wissen nicht mal was der Profiler ist. Und die anderen meiden ihn meist wie der Teufel das Weihwasser. Nicht ganz zu unrecht - denn er ist kompliziert und es kostet viel Zeit sich damit auseinanderzusetzen. Aber der UE4 Profiler ist ein extrem professionelles Tool um zu messen was in eurem game wie viel Ressourcen verbrät. ABer auch wenn ihr euch nicht viel mit dem Profiler auseinandersetzt und ihn nur mallaufen lässt ist er schon sehr wertvoll durch die Kennzahlen CPU und GPU. Verbrätder Render thread bei euch 99% - dann Gratulation - es ist wirklich nur die Grafik. Ihr habt was Event tick ud co angeht nix dummes gemacht. Gibt esneben dem Render thread aber noch andere "Fresser", dann müsste man sich die eigentlich programmierung ansehen. Habt ihr einen "On Tick" überladen? Nutzt ihr zu viele "get all actors..." Abfragen? Oder zu komplizierte Schleifen?


    5. Render thread - oder: Hilfe die Grafikkarte glüht

    Das ist wohl meist das Problem. Ja klar ein 3D Spiel nutzt die 3D Karte schon. Aber oft gibt es hier was zu optimieren. Hier gibt der Viewport schnelle Hilfe. Standard ist die Ansicht "Lit" im viewport - verwendet mal "Optimization Viewmodes". Interessant sind hier "light Complexity" und "Shader Complexity", was euch einen Überblick gibt wo Lichter und wo Materialien sehr teuer zu errechnen sind.


    6. Materialien - muß man alles haben?

    Das UE4 default Material ist sehr genügsam. Transparente und reflektierende Materialen dagegen kosten mehr. Könnt ihr in eurem 4K Monitor die Material nodes nicht auf einer Seite darstellen dann ist das ein zeichen für ein recht komplexes Material. Wie zuvor erwähnt - Shader Complexity gibt euch da gute Anhaltspunkte. Ist hier alles Rot sind Materialien komplex zu berechnen. Nicht nur der Transparenz Modus ist ausschlaggebend - könnt ihr auch mal roughness auf 1 stellen? Muß es reflektieren? Das kostet viel GPU. Dann gibt es noch Texturen. also zum nächsten Punkt.


    7. Texturen - muß es 4K sein?

    Klar wenn eine riesige Wand eine Textur ist dann macht das auch mal Sinn die in 4K zu haben. ABer muß eine Streichholzschachtel oder die Seite eines Würfels 4K haben? Hier muß man mal überlegen a la "Wenn der User eine 4K AUflösung hat (Selten!) und sich dann eine Seite des Würfels anschaut - dann müsste sie schon den ganzen Bildschirm füllen damit er immer noch eine perfekte nicht downscaled textur sieht". Jetzt die Quizfrage - wird er jemals an den Würfel so extrem nahe kommen daß eine Seite den ganzen Bildschirm füllt? Wenn nein dann ist das ein Kandidat um die textur extrem zu verkleinern. Ihr haut euch nur den texture streaming pool unnötig voll wenn ihr alle mini Objekte mit 4K texturen ausstattet. Überlegt mal wie nah man den kommt und es ist manchmal gar nicht so schlimm wenn mal ne 4K textur auf einem 8K Screen in fullscreen erscheint. meist sitzt man eh nicht so nah davor und das Anti-Aliasing macht es sehr viel schöner. Mal reduzieren und probieren.


    8. LOD oder wie ich aus 10 millionen Polygonen 10.000 machte

    UE4 macht auto-LOD. Dumm nur wenn eure Modelle gar keine LODs haben. LOD heisst "Level of Detail". Sprich je weiter weg die Objekte desto weniger detailliert. Gibt geile Plugins wie "InstaLOD", mit denen man sehr komplexe Modelle in den höheren LODs stark reduzieren kann. Nutzt das wenn Polygone der Killer sind.


    Manche Modelle die eh nur aus Entfernung sichtbar sind kann man grundsätzlich downscalen, also mal probieren.



    So ich bin erst mal platt vom Schreiben. Vielleicht erweiter ich das bei zeiten.

    • Offizieller Beitrag

    Was ich grad nebenbei bisschen teste, ist streaming. Die Funktion sollte man neben den LOD nicht so ganz unterschätzen. Besonders wenn man geschlossene Räume hat, ist Streaming sehr genial und man kann auch mal etwas mehr Details darstellen, bevor es Probleme mit der Performance gibt.

    Den Job sollte ja eigentlich das Culling übernehmen. Schaut man von außen durch ein Fenster in einen Raum sollte auch nur das sichtbar sein was der Player sieht.

    Nur stellt man sich natürlich die Frage ob wirklich alles ausgeblendet wird. Man kann Objekte die durch das Culling ausgeblendet wurden durch einen Konsolenbefehl anzeigen: r.VisualizeOccludedPrimitives 1


    Wenn von LODs geredet, denkt man meist an den Polycount aber man kann durch LODs auch verschiedene Texturen verwenden und die 2K Textur erst aus der nähe einblenden.

    4k Texturen verwendet man eigentlich nie, hier kann man auch auf Kachelbare Texturen oder Vertexpaint in Verbindung mit Decals setzen. Man muss sich auch überlegen ob eine riesige Wand Sinn macht.


    Was auch wichtig ist: Man redet im vom Culling aber Objekte muss auch Cullingbar sein.


    Hier mal ein Beispiel:

    Wenn man eine Stadt baut, dann kann man dem Player einen Wolkenkratzer vor die Nase setzen. Der Wolkenkratzer besteht aus einem einzigen Objekt und einem Polycount von 2 Millionen.

    Der Wolkenkratzer ist fast von überall aus der Karte zu sehen, es werden also immer 2 Millionen Tris angezeigt wenn man keine LODs verwendet.

    Selbst wenn man aus einem Schlüsselloch den Wolkenkratzer schaut, muss alles angezeigt werden, die vollen 2 Millionen Tris.

    Würde man den Wolkenkratzer nur in Fassadenteile und innenteile ausspliten so haben die Fassadenteile vielleicht 25000 Tris und das innere mit Möbel den Rest.

    Schaut man auf den Wolkenkratzer aus weiter Entfernung werden nur die Fassadenteile angezeigt und man spart sich sehr sehr viel Performance mehr als wenn man vom Wolkenkratzer LODs erstellt hätte.

    Die Grundfrage ist also:

    Lieber viele Objekte zu einem Objekt Mergen, dafür einen höheren Polycount im gesamten oder lieber einzelne Objekte bei dem nicht sichtbare Objekte konstanz ausgeblendet werden.

    Beide Varianten haben vor und Nachteile.

    • Offizieller Beitrag

    Culling ist das darstellen eines Objekts. Streaming ist das Löschen oder Laden einer gesamten/einzelnen Szene/Map.

    Ich wäre mir da nicht so sicher ob das ein Unterschied macht. Culling verfahren gibts in unreal.


    Durch das Backface Culling ist immer nur das sichtbar was der Spieler sieht alles andere ist nicht da und muss auch nicht von der Grafikkarte gezeichnet und berechnet werden. (Generiert also auch keine Drawcalls)


    Der Vorteil beim Levelstreaming ist für mehr die Möglichkeit das Spiel zu starten und während man sich im Menü befindet, das Spiel im Hintergrund weiter laden zu lassen.

    Auch kann man während des Spielens und der Spieler läuft zb auf eine Levelgrenze zu, bereits das neue Level im Speicher laden und somit vorbereiten. Erreicht der Spieler die Levelgrenze geht das Laden schneller.


    Lass mich da gerne eines besseren belehren:


    Das Culing blendet alles aus wirklich alles außer das was durch den Player noch sichtbar ist.

    Warum also Levelstreaming ? Das Levelstreaming ersetzt nicht das Culling.

    Was mich dann auch interessieren würde ist, wie die Sublevels aufgeteilt werden müssten damit es Sinn ergibt ? Wenn man alle Steine in ein Sublevel steckt, und alle Häuser ist doch deswegen nichts performanter.

    Streaming ist ja nichts anderes als Layer in die Objekte gepackt werden können. Jedes Streaming Level kann zu einer beliebigen Zeit geladen und entladen werden.

  • Zum Festhalten:



    Streaming eher Ladezeit Optimierung bzw Vorladezeit Optimierung.

    Das Culling ist eher für Echtzeit Performance zuständig.

    Man könnte durch streaming schon etwas sparen weil man potentiell CPU fressende Teile wegbekommt, die sinnlos berechnet werden. Wobei die Frage ist ob streaming hier wirklich hilft, da du mit Fileoperationen anfängst und die sind sehr langsam. Da macht optimering wie z.B. eine Art eigenes Processing LoD zu implementieren. D.h. bestimmte prozesse eines Objekts werden ignoriert oder vereinfacht modelliert bis sie relevant werden.

    Am Ende ist das ganze ein Balanceakt, man muss wissen wo man noch Luft hat und wo nicht, und danach arbeiten.


    BTW zum Thema. Hier gibts etwas zum GPU Profiler, der ist wenn man dann weiß, dass die GPU der Bottleneck ist, ganz praktisch um herauszufinden wo man Optimierungspotential hat. Link

    • Offizieller Beitrag

    Man könnte durch streaming schon etwas sparen weil man potentiell CPU fressende Teile wegbekommt, die sinnlos berechnet werden. Wobei die Frage ist ob streaming hier wirklich hilft, da du mit Fileoperationen

    Ich frage mich wie du die wegbekommen willst ?


    Ersparnis hast du ja nur wenn du etwas nicht berechnen musst, was du normalerweise hättest berechnen müssen oder ?

    Streaming Läd etwas oder tust es nicht. Verstehe nicht wie man da Optimieren kann ?


    Wie gesagt bei der Ladezeit Optimierung glaube ich das durchaus aber in der Echtzeit Performance glaube ich nicht an große Einsparungen durch Streaming. Da würde ich eher aufs Culling setzen.


    Laut Gene Amdahl glaube ich auch nicht an die unendliche Optimierung, bei beim Polycount muss man sich manchmal auch überlegen ob es die Arbeit der Optimierung wirklich Wert ist.

    Ich hab da auch kaum Vergleichs Erfahrungen finde das Thema aber spannend.

  • Die Idee dahinter ist, dass du mit level streaming, dafür sorgst, dass nur die nötigsten Objekte existieren. D.h. du musst nicht deren Ticks, Physik, etc berechnen, das Zeug läuft ja auch trotz Culling weiter und auch im suchalgorithmus der hinter dem Culling steckt, werden diese Objekte ja beachtet. Was nicht existiert wird auch nicht berechnet, ist hier die Grundidee.

    Ob du damit aber wirklich sparst ist aber eine andere Frage. Man kann genauso gut, dafür sorgen, dass du mit dem Streaming dein System mehr belastest und nichts gewinnst, weil du ja dauernd laden, entladen, initialisieren, zerstören, etc musst. Auch ist es in einem Deferred Renderer eher so, dass das Zeug was man auch auf dem Bildschirm wirklich sehen kann Probleme macht. Daher halte ich das Levelstreaming auch nicht für eine tolle Lösung.


    Der use-case und die Randbedingungen sind entscheidend. Daher ist eine gute Analyse über die ganzen Profiler-Tools wichtig, denn wie du sagst ist es sinnlos dort zu optimieren wo nicht viel zu holen ist. Am besten sollte man sich auch genaue Ziele oder Kriterien setzen, damit klar ist, wie man den Erfolg seiner Optimierung misst, um schnell zu erkennen ob man hier überhaupt in die richtige Richtung geht. Auch das Kosten/Wirkungs-Verhältnis ist ein wichtiges Kriterium, bei der Bewertung einer Maßnahme, vielleicht setzt man dann lieber einfach die Minimal Systemanforderung etwas höher, das löst es ja auch.


    Generell ist es schwer bis unmöglich hier ein universelles Rezept zu schreiben, da Optimierung eine recht komplexe Disziplin ist, von der ich auch nur Grundlagen kenne.

    Wie gesagt, bei Grafik erst mit Stat Unit anfangen um zu sehen ob das Problem die DrawCalls oder die GPU Frametime ist. Bei Drawcalls ist glaube ich klar, was zu tun ist (zusammenfassen, löschen), GPU Frametime benötigt mehr analyse über den Profiler, der dir Auskunft gibt, was überhaupt dein Problem ist (Licht, Effekte, Render Targets, etc.) bzw wo die low-hanging-fruits stecken.


    Also: Nicht einfach ungezielt drauflos optimieren, sondern erstmal schauen was man machen muss. Wenn man z.B. einen Monat Arbeit reinsteckt um Polys zu optimieren und dann merkt, man holt damit nur einen Bruchteil einer Millisekunde raus, dann ist es verschwendete Zeit/Geld.

    • Offizieller Beitrag

    Ganz genau so sehe ich das auch.


    Auch entwickelt sich ein Level mit der Zeit neu meshes verändern sich werden ersetzt oder fliegen raus.


    Ich als Artist kann den Polycount nicht von Anfang an abschätzen der er sich mit mit meinen Ideen entwickelt. Zum Testen verwende ich auch oft ein MIdpoly was eher einen hohen Polycount hat aber wichtig ist damit ich mir das Ergebnis (Das Envoirement) besser vorstellen kann.


    DIe Performance Optimerung kommt dann nach und nach. Ich will damit auch nur sagen, das man sich wegen der Performance nicht ab der ersten Sekunde Gedanken machen muss.

  • Performance Optimierung machen die meisten erst wenn die Hütte am brennen ist.


    Level streaming, LOD und optimierung von FUnktionen macht man ja meist nicht aus Spaß oder langweile sondern weil die FPS halt nicht halen was man versprochen hat.


    Sleepy: Ich glaube du unterschätzt LOD. Gerade in sehr großen Maps macht das viel aus. Zumindest wenn man sehr viele sehr komplexe objekte hat. Aber klar es muss überlegt sein oder man hat nen wirklich guten workflow dafür.


    Klar in nem Puzzlespiel musst du dir darum keine Gedanken machen, aber wenn du ein Open World Multiplayer Spiel mit sehr weiter Sicht machst dann lohnt es sich nicht erst 3 Tage vor Release damit anzufangen.

    • Offizieller Beitrag

    Ich glaube du unterschätzt LOD.

    Ich hab doch nichts schlechtes über LODs gesagt man muss sie nur eben auch richtig anwenden.


    Optimierung ist eine sehr Zeitfressende Geschichte und dafür gibt es auch kein Patent Rezept.


    ZU LODs: Ich gehe jetzt mal nicht davon aus das ihr auf Konzept Zeichnungen zurückgreifen könnt, das heißt ihr baut Eure Modelle aus dem Kopf heraus. Meine Modelle passen niemals von Anfang an, und sind niemals beim ersten mal so wie ich sie mir vorstelle.

    Wer nur ein Stuhl hat, kann sich nicht vorstellen wie der Tisch dazu aussehen soll, wer nur den Tisch hat kann sich den Stuhl nicht vorstellen. Das heißt alles muss mehr oder weniger zusammenwachsen.

    Grundgerüst und dann alles hochziehen.


    Wenn sich also die Modelle ständig ändern, macht auch das erstellen der LODs keinen Sinn, zumindest nicht im früheren Stadium.


    Klar kann man sagen, LODs sind klasse, Levelstreaming ist spitze und den Polycount flach halten.

    Aber ehrlich, was bringen diese Informationen in der Praxis ?


    Auch mal als Beispiel: Wenn ich ein Realistischen AAA Haus Modellieren möchte, dann kann ich das nicht als Lowpoly aus ein paar Planes zusammen nageln. Das sieht nicht so aus wie in meiner Vorstellung. Damit es so aussieht wie in meiner Vorstellung, brauche ich ein Midpoly und das ist eben nun nicht performant.


    Erst die Idee und die Optimierung am Schluss. Das ist meine Meinung dazu.