2 Punkte von GN⁺ 2023-11-06 | 1 Kommentare | Auf WhatsApp teilen
  • Obwohl Cities: Skylines 2 ein simulationslastiges Genre bedient, fällt in den meisten Situationen vor allem ein GPU-Flaschenhals auf; Benchmarks zeigen, dass man selbst für 1080p bei 60 FPS mit mindestens mittleren Einstellungen eine Grafikkarte der Klasse von etwa 1000 bis 2000 Euro braucht
  • Ein mit Renderdoc aufgezeichneter Beispielframe zeigt 87,8 ms, 6705 Draw Calls, mehr als 50.000 API-Calls und rund 6,7 GB GPU-Puffer- und Texturspeicherverbrauch und liegt damit weit über den für 60 FPS nötigen 16,7 ms
  • Der Kern des Flaschenhalses ist das Fehlen von LODs bei vielen Meshes und simples Culling, wodurch hochpolygonale Geometrie, die kaum zum Bild beiträgt, wiederholt gerendert wird; allein der Schatten-Pass beansprucht 40 ms und 72 % aller Draw Calls
  • Die umstrittenen Bürgerzähne werden tatsächlich gerendert, sind aber nicht die alleinige Ursache; problematischer ist die Summe aus überhöhter Vertex-Zahl und ineffizientem Rendering bei Bürger-Modellen, Props und Dekorobjekten allgemein
  • Die Integration von Unity DOTS und HDRP wirkt unreif, sodass Colossal Order offenbar ECS-Renderer-Anbindung, Culling und virtuelles Texturing selbst implementiert hat; CPU-Flaschenhälse wurden zwar reduziert, die Grafik-Pipeline scheint jedoch noch nicht ausreichend ausgereift

Performance-Probleme vor und nach dem Release

  • Schon vor der Veröffentlichung von Cities: Skylines 2 gab es angehobene empfohlene Systemanforderungen, eine Verschiebung der Konsolenversion auf 2024 und Einschränkungen bei Aussagen zur Performance
  • Eine Woche vor dem Release veröffentlichte Colossal Order eine Mitteilung, die fast wie eine vorbeugende Rechtfertigung der Performance-Probleme wirkte; nach dem Start wurde die Leistung dann nahezu universell kritisiert
  • Städtebauspiele erreichen oft keine hohen Framerates, doch bei diesem Spiel fällt statt des genretypischen CPU-Limits vor allem ein GPU-Flaschenhals auf
  • Laut Benchmarks von PC Games Hardware und Gamers Nexus wird für 1080p bei 60 FPS bereits ab der Einstellung „very low“ eine GPU im Bereich von etwa 1000 bis 2000 Euro benötigt
  • Auf einem System mit RTX 3080, Ryzen 7 5800X und 5120×1440-Monitor lag das Hauptmenü beim ersten Start unter 10 FPS; nachdem wie von den Entwicklern empfohlen depth of field, motion blur und volumetric effects deaktiviert wurden, stieg die Bildrate auf etwa 90 FPS
  • Auf einer leeren Karte wurden etwa 30 bis 40 FPS erreicht, und auch nach rund einer Stunde Spielzeit blieb das Niveau mit gelegentlichen Rucklern ähnlich

Engine und Rendering-Struktur

  • Cities: Skylines 2 basiert auf Unity 2022.3.7 und nutzt Unitys DOTS, ECS und den Burst compiler
  • Dank DOTS scheint das Spiel mehrere CPU-Kerne deutlich effizienter zu nutzen als sein Vorgänger
  • Die Spiel-Logik besteht laut Code aus rund 1200 Systemen, und praktisch fast die gesamte Logik scheint auf einer ECS-Struktur zu basieren
  • Für die UI wird nicht Unity UI Toolkit, sondern das auf HTML, CSS und JavaScript basierende Coherent Gameface verwendet
    • Im JS-Bundle finden sich Spuren von React und Webpack
    • Die UI kann bei Wartung und Änderungen Vorteile haben, ist laut den analysierten Daten aber kein zentraler Flaschenhals
  • Für die Grafik kommen Direct3D 11 und Unity HDRP zum Einsatz
  • Um ein mit DOTS/ECS gebautes Spiel an Unitys bestehendes Rendering-System anzubinden, ist eine eigene Zwischenschicht nötig, doch Cities: Skylines 2 scheint nicht Unity Entities Graphics zu verwenden
    • Skinning und Occlusion Culling in Entities Graphics sind als experimental markiert
    • virtual texturing wird nicht unterstützt
    • Stattdessen scheint mit BatchRendererGroup und Low-Level-Code eine eigene Anbindungsschicht umgesetzt worden zu sein

Analyseumgebung mit Renderdoc und ihre Grenzen

  • Für die Rendering-Analyse wurde Renderdoc verwendet
  • Bei der Game-Pass-Version konnten Renderdoc und NVidia Nsight Graphics wegen Sandboxing oder Dateiberechtigungen nicht auf die ausführbare Datei zugreifen
  • Auch bei der Steam-Version war eine Verbindung mit Renderdoc auf normalem Weg wegen Paradox Launcher und Steam-Authentifizierung schwierig; letztlich gelang die Aufzeichnung über den Global Process Hook von Renderdoc
  • NVidia Nsight Graphics funktionierte, indem Steam in Nsight geöffnet und das Spiel darin gestartet wurde, doch unter D3D11 werden viele Profiling-Funktionen nicht unterstützt, sodass nicht deutlich mehr Informationen als mit Renderdoc gewonnen wurden
  • Der analysierte Frame wurde in einer Stadt mit rund 1000 Einwohnern aufgenommen
    • Die Spielversion war 1.0.11f1
    • Der neueste Patch 1.0.12f1 enthält einige Verbesserungen, behebt die Probleme aber nicht vollständig
    • Die von Renderdoc gemessene Frame-Zeit lag bei 87,8 ms, entsprechend etwa 11,4 FPS
    • Da die tatsächliche Spielpraxis im Schnitt bei 30 bis 40 FPS lag, ist ein Overhead durch Renderdoc oder ein Ausreißerframe möglich

Rendering-Metriken des Beispielframes

  • Die von Renderdoc gemeldeten Frame-Statistiken lauten wie folgt
    • Draw calls: 6705
    • Dispatch calls: 191
    • API calls: 53361
    • Index/vertex bind calls: 8724
    • Constant bind calls: 25006
    • Resource update calls: 1679
    • Textures: 342, etwa 3926 MB
    • Render targets: 180, etwa 2328 MB
    • Buffers: 4144, etwa 447 MB
    • Gesamtsumme aus GPU-Puffern und Texturen: etwa 6,7 GB
  • Ein VRAM-Verbrauch von 6,7 GB ist für eine vergleichsweise einfache Szene hoch, zumal es weiterhin aktuelle Mittelklasse-GPUs mit 8 GB VRAM gibt
  • Laut ergänzender FAQ-Analyse umfasst das Rendering dieses Frames 121 Millionen Input-Vertices und rund 36 Millionen rasterisierte Dreiecke
    • Das ist nicht die Zahl der tatsächlich sichtbaren Polygone, sondern die Gesamtmenge an Geometrie, die über alle Render-Pässe hinweg verarbeitet wurde
    • Auf Reddit gibt es Berichte, dass in größeren Städten mehrere hundert Millionen Vertices und in bestimmten Situationen bis zu einer Milliarde Vertices pro Frame erreicht werden

DOTS-Instancing und GPU-Datenupdates

  • Fast alle Draw Calls verwenden Instancing
  • Das Spiel speichert alle für das Rendering von Objekten nötigen Instanzdaten in einem einzigen großen Puffer
  • Normale Spielobjekte scheinen pro Instanz etwa 50 Floats zu verwenden, Straßen offenbar noch mehr Daten
  • Die Instanzdaten aller sichtbaren Objekte werden pro Frame im Puffer aktualisiert und zur GPU hochgeladen
  • Der Puffer beginnt bei rund 60 MB und wird bei Bedarf auf größere Größen neu allokiert
  • Dieser Puffer wird bei fast allen Draw Calls genutzt und ist laut Renderdoc sowohl im Vertex Shader als auch im Pixel Shader zugreifbar
  • Dadurch können bei jedem Vertex zusätzliche Pufferzugriffe anfallen, was sich mit dem Problem hochpolygonaler Meshes verstärken könnte

Simulation und virtuelles Texturing

  • GPU-Compute-Shader werden für grafikbezogene Simulationen wie Wasser, Schnee, Partikel und Skelettanimation eingesetzt
  • Zusammengenommen beanspruchen diese Arbeiten nur rund 1,5 ms und damit weniger als 2 % der gesamten Frame-Zeit
  • Die frühe Vermutung, das eigentliche Simulationssystem werde massenhaft auf die GPU ausgelagert, wird durch dekompilierten Code und GPU-Calls nicht gestützt
  • Cities: Skylines 2 scheint ein eigenes System für virtuelles Texturing/Textur-Streaming implementiert zu haben
    • Unitys integriertes Streaming Virtual Texturing befindet sich weiter in einem experimentellen bzw. nicht unterstützten Zustand
    • Das Spiel scheint virtuelles Texturing bei den meisten statischen 3D-Objekten außer dem Terrain zu verwenden
  • Virtuelles Texturing kann Speicher sparen, indem nur benötigte Texturkacheln geladen werden, doch in der aktuellen Implementierung werden selbst auf nahen Oberflächen teils keine hochauflösenden Texturen geladen
  • Auch die fehlende Unterstützung für anisotropic texture filtering könnte mit der Nutzung von virtuellem Texturing zusammenhängen
  • Dieser Pass benötigt rund 0,5 ms

Kosten der wichtigsten Rendering-Pässe

  • Skybox generation

    • Mit dem physikalisch basierten Himmelssystem von Unity HDRP wird pro Frame eine Cubemap erzeugt
    • Das kostet etwa 0,65 ms und entspricht bei 60 FPS fast 4 % des Frame-Budgets
  • Pre-pass

    • Im ersten Schritt des Deferred Renderings werden depth, normal und geschätzte smoothness in separate Texturen geschrieben
    • Dieser Pass ist mit rund 8,2 ms sehr schwergewichtig
  • Motion vectors

    • Per-Pixel-Motion-Vektoren für anti-aliasing und motion blur werden in einem separaten Pass gerendert
    • Das kostet rund 0,6 ms
    • Die Motion-Vektoren wirken teilweise fehlerhaft, weshalb das Spiel zum Zeitpunkt des Artikels kein DLSS oder FSR2 unterstützt
  • Roads and decals

    • Hier werden Straßen, Gras und an die Terrainoberfläche angepasste Elemente gerendert
    • Das kostet etwa 1 ms
  • Main pass

    • Der Kern-Pass des Deferred Renderings erzeugt mithilfe der bisherigen Puffer und des virtuellen Textur-Caches albedo, normal, PBR-Eigenschaften, depth und weitere Daten
    • Auch die Sichtbarkeitsinformationen für virtuelles Texturing entstehen hier
    • Offenbar wird mit halber horizontaler Auflösung gerendert, während das Terrain ohne virtuelles Texturing in voller Auflösung gerendert wird
    • Dieser Pass kostet rund 16,7 ms und entspricht damit allein dem gesamten für 60 FPS verfügbaren Zeitbudget
  • Ambient occlusion

    • Den Shader-Debug-Namen zufolge wird GTAO verwendet
    • Der Pass kostet etwa 1,6 ms
  • SSR + SSGI

    • Verwendet werden Unity HDRP screen space reflections und screen space global illumination
    • Beide Effekte zusammen kosten rund 3 ms
  • Deferred lighting

    • Die zuvor erzeugten Zwischenpuffer werden kombiniert und ergeben ein nahezu fertiges Bild
    • Das kostet etwa 2,1 ms
  • Water rendering

    • Die Wasseroberfläche wird mithilfe eines Compute-Shader-Vorlaufs sowie verkleinerter und weichgezeichneter Bildeingaben gerendert
    • Das kostet etwa 1 ms
  • Post-processing

    • Zum Einsatz kommen temporal AA, bloom, tonemapping sowie bei Aktivierung DOF und motion blur
    • Insgesamt fallen rund 1 bis 2 ms an
  • UI

    • Gerendert werden die auf Gameface basierende UI und Texte in der Spielwelt
    • Straßennamen werden als 2D signed distance fields gerendert und mithilfe des depth buffer mit der Szene verblendet, wenn sie hinter Gebäuden liegen
    • Der abschließende UI-Pass ist zeitlich vernachlässigbar

Die Zahn-Kontroverse und Charaktermodelle

  • Bürgercharaktere besitzen tatsächlich ein vollständiges Gebiss-Modell, das in der normalen Spielperspektive nicht sichtbar ist
  • Durch eine Analyse des Reddit-Nutzers Hexcoder0 mit NVidia Nsight Graphics wurde bekannt, dass die Zähne immer in maximaler Qualität gerendert werden
  • Das wichtigere Problem ist jedoch, dass die Charakter-Meshes insgesamt keine LOD-Varianten besitzen
  • Colossal Order hat dieses Problem öffentlich eingeräumt und auch allgemeinere LOD-Probleme erwähnt
  • Die Bürger-Modelle werden auf Basis von Didimo Popul8 erzeugt; das Zahn-/Mundmodell im Spiel hat 6108 Vertices und damit mehr als das Didimo-Basismesh mit 1060 Vertices
  • Ein einzelner Charakter kommt ohne Haare, Kleidung und Accessoires bereits auf etwa 56.000 Vertices
    • Ein durchschnittliches Wohngebäude mit geringer Dichte liegt ohne Garten-Props und Detailobjekte unter 10.000 Vertices
  • Im Beispielframe werden 13 Zahnsätze gerendert, ohne auch nur einen einzigen Pixel im finalen Bild zu beeinflussen
  • Die Zähne sind damit weniger die alleinige Ursache des Performance-Verlusts als vielmehr ein Beleg dafür, wie verbreitet unnötige hochpolygonale Geometrie ist

Hochpolygonale Props und Culling-Probleme

  • Das Spiel rendert viel zu viele Objekte mit viel zu hoher Polygonzahl, obwohl sie kaum oder gar nicht zum finalen Bild beitragen
  • Die Hauptursachen sind zwei Punkte
    • Bei manchen Modellen fehlen LOD-Varianten
    • Das eigene Culling-System ist simpel und scheint nur frustum culling zu implementieren; Hinweise auf occlusion culling gibt es nicht
  • Distanzbasiertes Culling ist vorhanden, aber nicht aggressiv, was Pop-in reduziert, der Performance jedoch schadet
  • Zu den im Beispiel identifizierten hochpolygonalen Props zählen
    • Palette mit Gasflaschen: mehr als 17.000 Vertices
    • Wäscheleinen-Prop: 25.000 Vertices pro Stück, die dichtere Variante sogar mehr als 30.000 Vertices
    • Parkhäuschen: mehr als 40.000 Vertices, ohne LOD; selbst die Verbindungskabel von Monitor und Tastatur sind einzeln modelliert
    • Holzstapel: mehr als 100.000 Vertices
  • Wenn Gebäude und Innenraum-Props zu einem einzigen Mesh zusammengefasst werden, sinkt zwar die Zahl der Draw Calls, einzelne Innenobjekte lassen sich dann aber nicht mehr separat cullen
  • In einem Städtebauspiel kann dasselbe ineffiziente Modell in einem Frame hunderte Male gerendert werden, sodass sich selbst kleine Verschwendungen summieren
  • Hochauflösende Modelle an sich sind nicht das Problem; das eigentliche Problem ist, dass das Spiel diesen Detailgrad derzeit nicht bewältigt und die Polygonnutzung ineffizient sowie inkonsistent ist

Der Schatten-Pass ist der größte Flaschenhals

  • Cities: Skylines 2 verwendet cascaded shadow mapping
  • Die Schatten zeigen viele Artefakte und Flickering, besonders wenn sich Sonne oder Blätter bewegen
  • Das Spiel nutzt vier Cascades mit einer Auflösung von 2048×2048 pro Cascade
  • In den erweiterten Grafikoptionen gibt es zwar eine Einstellung für directional shadow map resolution, doch zum Zeitpunkt des Artikels ist sie im Code offenbar nicht angeschlossen
    • Weder einzelne Optionen noch die globale shadow quality verändern die shadow map resolution
    • Die Presets medium und high sind faktisch identisch
    • Das low-Preset deaktiviert Schatten, die vom Terrain geworfen werden
  • Trotz der eher geringen Qualität ist Shadow Mapping mit rund 40 ms der langsamste Rendering-Pass
  • Von den 6705 Draw Calls des Beispielframes entfallen 4828, also 72 %, auf das Shadow Mapping
  • Offenbar behandelt das Spiel alle 3D-Objekte unabhängig von Größe oder Entfernung und bei jeder Qualitätsstufe als potenzielle shadow caster
  • In den Performance-Zählern von Renderdoc beeinflussen viele Draw Calls weniger als 100 Pixel der Shadow Map oder gar 0 Pixel; auch die Zähne tauchen im Schatten-Pass erneut auf
  • Verbesserungen bei LOD und Culling könnten die Shadow-Mapping-Performance stark beeinflussen
  • Ein positives Detail ist, dass das Spiel die Position von Sonne und Mond anhand von aktuellem Datum, Uhrzeit und Koordinaten der Stadt berechnet

Performance-Probleme im Hauptmenü

  • Das Hauptmenü wirkt wie ein statisches Hintergrundbild mit Buttons, tatsächlich existiert aber permanent eine 3D-Szene
  • Hinter dem Menü wird eine Szene mit Terrain, Wasser und Skybox gerendert, die anschließend vollständig von der UI überdeckt wird
  • Da für diese unsichtbare Szene die komplette Rendering-Pipeline läuft, wirken sich Grafikoptionen sofort auch auf die Performance des Hauptmenüs aus
  • Zum Release standen die meisten Einstellungen standardmäßig nahe am Maximum, einschließlich schwerer Effekte, deren Deaktivierung die Entwickler selbst empfohlen hatten
  • Der Grund für den Einbruch auf etwa 7 FPS beim ersten Start ist allerdings nicht vollständig geklärt
    • Ein vergleichbarer Leistungseinbruch ließ sich später nicht reproduzieren
    • Beim ersten Start wird zwar Arbeit für die Verarbeitung des virtuellen Textur-Caches ausgeführt, ob dabei die GPU genutzt wird, ist aber unklar
  • Die gesamte Hauptmenü-Szene umfasst rund 400 Draw Calls, 563.000 Input-Vertices und 745.000 rasterisierte Dreiecke

Ergänzungen aus der FAQ

  • Ob das Spiel besser mit Unreal Engine 5 entwickelt worden wäre, lässt sich nicht eindeutig sagen
    • UE5 bietet mit Nanite, Lumen und Virtual Shadow Maps Technologien, die einige der Probleme von C:S2 adressieren könnten
    • Andererseits fehlen produktionsreife Funktionen für umfangreiche Spiel-Logik und Simulationen auf dem Niveau von Unity ECS, und die stärker auf C++ ausgerichtete Struktur könnte bei Modding-Flexibilität und Zugänglichkeit nachteilig sein
  • Das Spiel hat nicht überhaupt keine LODs
    • Viele Gebäude scheinen passende LODs zu besitzen
    • Bei Rohren, Garten-Props und Dekorobjekten fehlt LOD jedoch oft oder wird nicht ausgewählt
  • InstaLOD wird offenbar in der Asset-Pipeline des Spiels genutzt, besonders wenn in den Mod-Tools neue Assets importiert werden, aber nicht im Runtime-Rendering
  • Die JavaScript-basierte UI ist laut den Analysedaten kein zentraler Flaschenhals
    • Gameface basiert nicht auf einer vollständigen Browser-Engine wie Electron, sondern ist ein speziell für Spiele-UIs gebautes Framework
    • Laut Beschreibung sollte es bei Speicherverbrauch und Performance günstiger sein als Chromium/Blink- oder WebKit-basierte Ansätze
  • Renderdoc hat als Präzisions-Benchmark-Tool Grenzen, liefert aber genug Belege dafür, warum das Spiel langsam ist

Fazit: CPU-Flaschenhälse reduziert, GPU-Pipeline aber fast unfertig

  • Der direkte Grund dafür, dass Cities: Skylines 2 die GPU so stark belastet, ist, dass die Grafikkarte mit unnötig viel Geometrie gefüttert wird
  • Diese Geometrieverschwendung entsteht durch fehlende LODs bei vielen Meshes und eine einfache, wenig abgestimmte Culling-Implementierung
  • Dass eine eigene Culling- und Rendering-Anbindungsschicht gebaut wurde, liegt vermutlich daran, dass die Integration von Unity DOTS und HDRP noch in Arbeit ist und für ein echtes Spiel zu viele Grenzen hatte
  • Auch Unitys virtuelles Texturing befindet sich in einem experimentellen Zustand, weshalb Colossal Order eine eigene Lösung implementiert hat, die ebenfalls noch nicht vollständig ausgereift wirkt
  • Plausibel ist daher, dass Colossal Order mit Unitys neuer DOTS-Technologie auf geringere CPU-Flaschenhälse und größere Simulationen gesetzt und dort auch Erfolge erzielt hat, grafisch aber Systeme wie Culling, Animation und Textur-Streaming selbst umsetzen musste
  • Die Behauptung der Entwickler, das Spiel sei von Anfang an auf 30 FPS ausgelegt gewesen, wird als wenig glaubwürdig bewertet und erscheint für ein reines PC-Spiel angesichts der Grafikqualität kaum als überzeugende Rechtfertigung
  • Bereiche mit besonders hohem Lösungspotenzial sind zusätzliche LODs, besseres Culling, optimierte Auswahl von shadow casters und eine Bereinigung der Assets auf Prop-Ebene; da viele Assets einzeln überarbeitet werden müssten, dürfte dies Zeit brauchen

1 Kommentare

 
GN⁺ 2023-11-06
Meinungen auf Hacker News
  • Es ist ein interessanter Artikel, daher würde ich mir wünschen, dass sich die Diskussion darauf konzentriert, was genau daran interessant ist.
    Solche Threads driften leicht in allgemeine Aussagen über $THING selbst ab, hier also das Spiel insgesamt, oder über $RELATED, hier Frameworks, oder über ähnliche Dinge im Allgemeinen.
    Das ist grundsätzlich nicht schlecht, aber mit jedem Schritt in Richtung Allgemeinplätze wird die Diskussion oberflächlicher und weniger interessant. Deshalb steht auch in den Site Guidelines „Vermeide allgemeine Nebendiskussionen“ - https://news.ycombinator.com/newsguidelines.html

  • Die Passage, dass „Colossal Order deshalb nicht das eingebaute Culling von Unity verwendet, sondern eine eigene Implementierung hat, weil die Unity-Integration von DOTS und HDRP noch immer mitten in der Entwicklung steckt und für die meisten echten Spiele als ungeeignet gelten kann, sodass sie große Teile der Grafik selbst implementieren mussten“, passt traurigerweise auch zu meinen Erfahrungen mit Unity-Tools.
    DOTS ist zwar veröffentlicht, aber wie bei anderen Tools, die Unity übernommen hat, fühlt es sich so an, als würde die Implementierung vernachlässigt. Im Unternehmen läuft operativ offenbar einiges massiv falsch, und wenn man sich den vor ein paar Wochen öffentlich eskalierten Vorfall um die Preispolitik ansieht, scheint der Fokus eher darauf zu liegen, den Nutzern noch mehr Geld abzunehmen, als die Engine zu verbessern.
    Bevys ECS-Implementierung ist wirklich gut, und ich hoffe, dass sie zusammen mit Godex in diesem Bereich Erfolg hat.

    • Ich verstehe nicht, wie Unity offenbar jedes Jahr bis zu 1 Milliarde Dollar Umsatz verbrennt und sich die Engine trotzdem noch wie ein halbgarer, unfertiger Zustand anfühlt. Wo fließt all dieses Geld hin?
    • Godex ist letztlich nur Lippenstift auf einem Schwein. Es kann die Performance etwas verbessern, aber ECS ist keine magische Optimierung, die man einfach wie ein Plugin darüberschraubt.
      Cache-Kohärenz auf der Gameplay-Ebene kann keine Engpässe auf Engine-Ebene beheben.
    • Ehrlich gesagt gibt es viele Wege, ein performantes Spiel auszuliefern, und ECS ist weder zwingend notwendig noch zwangsläufig der moderne Ansatz. Es ist eines von mehreren Architekturmustern, mit denen man ein Spiel strukturieren kann, und hat viele Vor- wie Nachteile.
      Godot etwa ist nicht ECS-zentriert, sondern basiert auf dem Konzept von „Servern“: eigenständigen Spiel-Subsystemen, die spezialisierte Bereiche wie Rendering und Physik weitgehend unabhängig behandeln und nur lose mit der allgemeinen Spiellogik gekoppelt sind.
      ECS-Architekturen stammen aus der Zeit von PS2/PS3, als CPUs ziemlich schlecht waren. Kleine Caches, hohe Kosten bei Branch-Mispredictions, langsamer Speicher, fragmentierte Speicherbereiche und das Fehlen von Speichern mit wahlfreiem Zugriff zwangen Entwickler dazu, Spiele auf vorhersehbare Speicherzugriffsmuster auszurichten. Daraus wurde eine Struktur üblich, bei der Spieldaten in kleinen Blöcken gestreamt und verarbeitet werden.
      Dieser Ansatz ist auch heute im Allgemeinen eine gute Praxis, aber mit extrem schnellen CPUs, hervorragender spekulativer Ausführung, guten Branch-Predictors und Caches im zweistelligen MB-Bereich ist er keine strikte Notwendigkeit mehr. Das gilt besonders, wenn man bedenkt, dass moderne Spiele den Umfang dessen, was auf dem Bildschirm passiert, gegenüber vor 10–20 Jahren gar nicht so stark vergrößert haben. Selbst in Actionspielen kämpft der Spieler immer noch selten gleichzeitig gegen mehr als ein Dutzend Gegner.
      Spiele, bei denen Tausende Elemente gleichzeitig auf dem Bildschirm erscheinen, brauchen normalerweise ohnehin eigene spezialisierte Logik und Verarbeitung.
    • Wurde DOTS nicht intern bei Unity entwickelt?
  • Tipp für alle, die dieses Spiel ausprobieren wollen: Resolution Scaling von dynamisch auf fest umstellen.
    Auf einer 3080 ging das Hauptmenü damit von „unspielbaren 10 fps“ zu „läuft im Spiel mit mittelhohen Einstellungen problemlos“.

    • Man kann es auch komplett ausschalten. Auf meiner 3080 scheint es ziemlich viele Rendering-Artefakte zu erzeugen.
    • Das ist nicht die Lösung. Man muss Motion Blur und Tiefenschärfe ausschalten. Vor allem die Tiefenschärfe killt die Menü-Performance.
  • Zum Vergleich: Ich meine mich zu erinnern, dass ein Frame in Crysis, bezogen auf die Benchmark-Szene, ungefähr 300.000 Vertices oder Dreiecke hatte. Je nachdem, in welche Richtung meine Erinnerung falsch liegt und wie schlecht das Vertex-/Dreiecksverhältnis der einzelnen Modelle ist, wären das also etwa 3–10 Stapel Baumstämme.

    • Ich bin der Autor: Ich habe in RenderDoc keine einfache Möglichkeit gefunden, die Gesamtzahl der Vertices pro Frame zu zählen, daher habe ich es nicht selbst gezählt. Auf Reddit hat jedoch jemand die Gesamtzahl der Vertices mit ReShade gemessen, und in Nahaufnahmen großer Städte könne sie demnach von mehreren hundert Millionen bis zu 1 Milliarde Vertices reichen.
      Edit: Ich habe die Zahl der Vertices und Polygone mit RenderDoc überprüft. Die Beispielszenen im Artikel verarbeiten 121 Millionen Vertices und über 40 Millionen Dreiecke.
    • Klingt plausibel. Ich erinnere mich, im Performance-HUD „1M Triangles“ gesehen und gedacht zu haben, dass eine Million Dreiecke völlig irre sind. Wenn man getrennte Kanten, Billboards usw. berücksichtigt, gibt es wahrscheinlich auch kaum geteilte Vertices.
  • Der Schreibstil war wirklich gut:
    Sätze wie: „Dieser Pass ist überraschend schwergewichtig, denn er dauert etwa 8,2 Millisekunden, also ungefähr absurd lange …“

    • Ich wünschte, mehr Leute würden selbst in etwas ernsteren Texten solche kleinen Witze einstreuen.
  • „Auch dieses Mesh eines Baumstapel wird nur im Shadow-Rendering-Pass verwendet und hat über 100.000 Vertices“ … aber warum?

    • Weil es in der Spieleentwicklung ungefähr eine Million Dinge gibt, auf die man achten muss. Wahrscheinlich hat jemand oder irgendeine Software bei den LOD-Einstellungen einen Fehler gemacht. Oder der dynamische LOD-Code hat das LOD0-Mesh nicht korrekt gecullt, oder man konnte diesen Code nicht rechtzeitig fertigstellen, oder es gibt einen ganz anderen Grund.
      Es ist völlig normal, dass AAA-Spiele einige unvollständige und nicht optimierte Elemente enthalten. Budgets sind immer begrenzt und Entwicklungszeiten kurz. Außerdem ist es eine hitgetriebene Branche ohne Erfolgsgarantie. Es gibt ein paar Wege, die Erfolgschancen eines Spiels zu erhöhen, aber die liegen meist eher im Management als in der Entwicklung, und prognostizierte Vorbestellerumsätze treffen selten genau zu. Deshalb muss man Risiken reduzieren, Kompromisse eingehen, Kosten senken, wo es möglich ist, und die teuersten Entwicklungsprioritäten nach unten schieben. Solche Kompromisse sind viel größer als ein einzelnes nicht optimiertes Mesh. Ein einzelnes Mesh ist nichts.
      Dass dieses Mesh LOD0 ist und auch das Zahn-Mesh LOD0 ist, ist eine interessante Tatsache. Aber allein dadurch bricht nicht die Performance des Spiels ein, und es sieht auch nicht wahrscheinlich aus, dass man statt echter Performance-Fixes genau das beheben wird. Die Fixierung auf solche Meshes in diesem Thread ist etwas übertrieben.
      Es gibt hier viele emotional aufgeladene Kommentare, und ich möchte dem nichts weiter hinzufügen, sondern nur mehr Kontext geben.
    • Man hätte das vermutlich mit etwa 100 Vertices und einer cleveren Normal Map lösen können; so ist es einfach wahnsinnig.
    • Das Studio hinter diesem Spiel hat ungefähr 30 Entwickler.
  • Stimmt die Zusammenfassung, dass das Spiel extrem detaillierte Modelle verwendet, aber keine Möglichkeit hat, Dinge, die nicht als tatsächliche Pixel erscheinen, clever zu abstrahieren oder zu cullen?
    Und falls ja: Lässt sich das leicht beheben, oder ist das so tief in der Kernarchitektur verankert, dass man zur Lösung beim Design neu ansetzen müsste?

    • Über den Schwierigkeitsgrad der Korrektur kann man nur spekulieren. Ich bin kein Experte, aber Culling und LOD sehe ich als große Säulen einer Engine. Wenn man die bestehende Implementierung nicht verwenden kann, ist das eine wirklich schlechte Lage.
      Die „Tricks“ an sich dürften gut bekannt sein, aber ich glaube nicht, dass die Implementierung einfach ist.
  • DOTS stammt aus den Ideen von Mike Action. Siehe seinen CppCon-Vortrag von 2014, „Data-Oriented Design and C++“ [1]. Laut Twitter hat Mike Unity allerdings verlassen.
    [1] https://www.youtube.com/watch?v=rX0ItVEVjHc

    • Der Originalbeitrag spricht zwar die rauen Kanten von DOTS an, aber ich habe darin nichts gesehen, was tatsächlich darauf hindeutet, dass DOTS die Ursache ist. Wenn DOTS das Problem wäre, würde es CPU-Overhead erzeugen; hier wirkt es eher so, als würden massenhaft völlig überdetaillierte Geometrien verwendet und kein LOD-System implementiert.
      Mit Nanite aus UE5 hätte man es vielleicht irgendwie durchstehen können, aber Geometrie in diesem Übermaß hätte alles andere zum Einsturz gebracht.
    • Meinst du den Mike Action, der auf Basis eines sehr zweifelhaften Datensatzes — abgesehen von Sportspielen und Ähnlichem — behauptet hat, dass sich 30-fps-Spiele besser verkaufen als 60-fps-Spiele?
  • Ich habe 40 Minuten damit verbracht, unter Proton Experimental bei 1080p selbst auf einer leeren Karte mehr als ein paar fps herauszuholen, dann aufgegeben und erstattet. Wenn sie die furchtbare Performance beheben, werde ich es noch einmal versuchen.
    Den ersten Teil habe ich wirklich sehr viel gespielt, daher ist es extrem schade, dass ich diesen Teil nicht ausprobieren kann.

    • Die Lösung passt in einen Tweet -> https://twitter.com/ColossalOrder/status/1716883884724322795
      „Wenn ihr Performance-Probleme habt, empfehlen wir, die Bildschirmauflösung auf 1080p zu senken, Tiefenschärfe und Volumetrics zu deaktivieren und die globale Beleuchtung zu reduzieren, während wir die Probleme beheben, die die Performance beeinträchtigen.“
      Das war alles, was ich getan habe, um auf einer AMD Radeon RX 5700 XT eine flüssige Performance zu bekommen.
    • Auf GeForce Now ist es ziemlich gut spielbar. Es ruckelt zwar trotzdem etwas, aber ich konnte mehrere Stunden ohne größere Probleme spielen. Gelegentlich gibt es nervige Hänger, aber sie sind erträglich.