1 Punkte von GN⁺ 2024-09-29 | 1 Kommentare | Auf WhatsApp teilen
  • GodotOceanWaves ist ein Rendering-Experiment, das in der Godot Engine mithilfe der inversen Fourier-Transformation eines gerichteten Meereswellenspektrums offene Meeresoberflächen erzeugt und mit zur Laufzeit per Skript anpassbaren Parametern verschiedene Meeresumgebungen simuliert
  • Gerstner waves eignen sich für niederfrequente Details ruhigen Wassers, stoßen bei rauen offenen Meeresoberflächen aber an Grenzen; dieses Projekt nutzt daher Spektren auf Basis empirischer ozeanografischer Daten und FFT
  • Die Wellenerzeugung folgt dem Tessendorf-Ansatz: Es wird ein initialer Spektralzustand erzeugt, über eine Dispersionsrelation zeitlich fortgeschrieben und anschließend per inverser Fourier-Transformation werden Displacement-, Normal- und Foam-Maps erzeugt
  • Das Rendering folgt dem BSDF aus dem Atlas-GDC-Vortrag, verwendet jedoch eine GGX-Verteilung; Foam wird in Bereichen akkumuliert und gedämpft, in denen die Jacobi-Matrix des Displacements negativ ist, und Sea Spray ist mit Godots GPUParticles3D und Custom Shadern umgesetzt
  • Mehrere Wave Cascades, einstellbare Update-Intervalle und Lastverteilung pro Cascade adressieren Tiling und GPU-Arbeitslast; Cascades müssen jedoch dieselbe Spektrum-Texturauflösung verwenden, und der partikelbasierte Sea-Spray-Ansatz skaliert bei höherer Dichte ineffizient

Was GodotOceanWaves macht

  • GodotOceanWaves ist ein Projekt zum Experimentieren mit dem Rendering offener Meeresflächen in der Godot Engine
  • Für die Wellenerzeugung wird die inverse Fourier-Transformation eines gerichteten Meereswellenspektrums verwendet
  • Die offengelegten Parameter sind kompakt gehalten und können per Skript in Echtzeit geändert werden, um verschiedene Meereswellen-Umgebungen zu simulieren
  • Als Demo-Videos sind ocean_demo.mp4 und environment_demo.mp4 enthalten

Warum Fourier-basierte Wellen statt Gerstner waves verwendet werden

  • Eine gängige Methode zur Animation von Wasser in Spielen ist es, Vertices mit Gerstner waves zu verschieben
  • Gerstner waves eignen sich gut, um niederfrequente Details ruhigen Wassers zu modellieren, reichen aber nicht aus, um die raue Oberfläche des offenen Meeres präzise darzustellen
  • Mit Meereswellenspektren auf Basis empirischer Daten, die von Ozeanografen gesammelt wurden, lässt sich direkter steuern, welche Wellen und Parameter geändert werden müssen, um einen bestimmten Meereszustand zu erzeugen
  • FFT hat mit O(N log N) eine geringere Komplexität als die klassische diskrete Fourier-Transformation mit O(N^2) und lässt sich auf parallele Systeme erweitern, wodurch sie gut für die Ausführung auf der GPU geeignet ist
  • Bei Gerstner waves muss jeder Thread Berechnungen für N Wellen durchführen, während bei FFT-basierten Wellen jeder Thread nur Berechnungen in der Größenordnung von log(N) ausführt

Shading, Foam und Sea Spray

  • Das Beleuchtungsmodell für das Meer folgt weitgehend dem BSDF aus dem Atlas-GDC-Vortrag
  • Für die Mikrofacettenverteilung wird statt Beckmann GGX verwendet
    • Der Grund ist, dass die flacheren und weicheren Highlights von GGX in mehreren getesteten Meereswellen-Umgebungen ein gleichmäßigeres Erscheinungsbild lieferten
  • Normal-/Foam-Maps werden mit einer Mischung aus bicubic und bilinear Filtering gesampelt, abhängig von der Pixeldichte im World Space
    • Bei niedriger Oberflächenauflösung werden Texture-Aliasing-Artefakte reduziert, bei hoher Oberflächenauflösung bleiben Details erhalten
  • Sea Foam wird nach Tessendorfs Methode dort erzeugt, wo sich Wellenkämme nach innen einrollen, also dort, wo die Jacobi-Matrix des Displacements negativ ist
    • Foam wird über mehrere Wellen-Updates hinweg linear in einer Textur akkumuliert
    • Die Parameter "foam grow rate" und "foam decay rate" steuern jeweils Akkumulation und exponentielle Dämpfung
  • Sea Spray ist mit Godots GPUParticles3D-Node und einem Custom Particle Shader umgesetzt
    • Partikel werden gleichmäßig auf einer Ebene innerhalb der Bounding Box von GPUParticles3D verteilt
    • Sie werden abhängig von der Foam-Menge an der jeweiligen Position gecullt, und nicht gecullte Partikel beginnen ihren Lebenszyklus mit einem zufälligen Offset
    • Jedes Partikel verwendet ein Billboard Sprite mit einer einzelnen statischen Textur
    • Während des Lebenszyklus werden Scale und Displacement verändert, um das Aussehen eines Splashs zu simulieren; ein Dissolve-Effekt im Mesh Shader vermittelt den Eindruck, dass Gischt in der Luft zerstäubt
  • Der größte Nachteil dieses Sea-Spray-Ansatzes ist, dass selbst eine starke Erhöhung der Partikelzahl die Dichte nur geringfügig steigert
    • Das liegt daran, dass die Partikel gleichmäßig in der Bounding Box verteilt sind und die meisten zusätzlich erzeugten Partikel gecullt werden

Pipeline der Wellensimulation

  • Die Methode zur Erzeugung der Oberflächenwellen folgt eng Tessendorf
  • Eine gerichtete Meereswellenspektrum-Funktion wird mit Zufallszahlen aus einer Gaussian distribution multipliziert, um den initialen Spektralzustand des Meeres zu erzeugen
  • Der initiale Zustand wird über eine Dispersionsrelation, die Frequenz und Ausbreitungsgeschwindigkeit der Wellen verknüpft, über die Zeit fortgeschrieben
  • Auf den fortgeschriebenen Zustand wird eine inverse Fourier-Transformation angewendet, um Displacement-Maps und Normal-Maps zu erzeugen
  • Die Implementierung besteht aus einer Compute-Shader-Pipeline, die Godots RenderingDevice-Abstraktion nutzt

Aufbau des Meereswellenspektrums

  • Die gerichtete Meereswellenspektrum-Funktion S(ω, θ) gibt die Energie einer Welle für eine gegebene Frequenz ω und Richtung θ zurück
  • Diese Funktion setzt sich aus der ungerichteten Spektrum-Funktion S(ω) und der Directional-Spreading-Funktion D(ω, θ) zusammen; beide Entscheidungen sind voneinander unabhängig
  • Für das ungerichtete Spektrum wird das von Horvath beschriebene Texel-Marsen-Arsloe(TMA)-Spektrum verwendet
    • TMA nutzt Windgeschwindigkeit U, Wassertiefe D und Fetch Length F
    • TMA kombiniert das vorausgehende JONSWAP-Spektrum mit einer Funktion zur Dämpfung durch die Wassertiefe
  • Für die Directional-Spreading-Funktion wird eine Mischung aus Horvaths flat und Hasselmann Directional Spreading über den spread-Parameter μ verwendet
    • Auch der von Horvath vorgeschlagene Parameter swell ξ ist enthalten, um die Elongation der Meereswellen zu modellieren
    • Das Hasselmann Directional Spreading wurde gewählt, weil es eine näherungsweise analytische Lösung für den Normalisierungsfaktor Q(σ) bietet
  • Gemäß Tessendorfs Vorschlag wird die resultierende Spektrum-Funktion außerdem mit einem Term zur Unterdrückung kleiner Wellen multipliziert
    • Dieser Term verwendet die Größe des Wellenzahlvektors k und den Parameter detail δ
  • Das finale gerichtete Meereswellenspektrum kombiniert TMA, mixed directional spread und small-wave suppression

GPU-FFT-Implementierung

  • Für FFT wird eine Custom-GPU-Implementierung in Compute Shadern verwendet
  • Statt Cooley-Tukey wird der Stockham-FFT-Algorithmus genutzt, um die initiale Bit-Reversal-Permutation zu vermeiden
  • Nach Flügge wird eine "butterfly"-Textur berechnet, die den Datenfluss der FFT kodiert
    • Diese Textur wird einmal neu berechnet, wenn sich die Spektrum-Texturauflösung ändert
  • Die 2D-FFT wendet zunächst den FFT-Kernel zeilenweise auf die Spektrum-Textur an
  • Anschließend wird die Textur per Compute Shader transponiert, sodass derselbe zeilenweise FFT-Kernel wie ein spaltenweiser FFT-Kernel wiederverwendet werden kann
  • Die Transposition ermöglicht nicht nur die Wiederverwendung der Pipeline, sondern verbessert auch die Speicherzugriffsmuster

Wave Cascades und Umgang mit Tiling

  • In der Ferne werden Tiling-Artefakte sehr deutlich, besonders wenn Sea Foam vorhanden ist
  • Das Wellenerzeugungssystem adressiert dieses Problem, indem es mehrere Wave Cascades gleichzeitig layern kann
  • Jede Cascade hat ihre eigene Tiling-Größe und ihren eigenen Parametersatz
  • Cascades können zur Laufzeit dynamisch hinzugefügt und entfernt werden
  • Da alle Cascades dieselbe Compute Pipeline verwenden, müssen sie dieselbe Spektrum-Texturauflösung haben
  • Alternativ lassen sich Wellen-Displacement und Normals mit Noise blenden, um Tiling-Artefakte bei geringeren Performance-Kosten zu reduzieren
  • Beim Überlagern von Cascades müssen Parameter und Größe jeder Cascade sorgfältig gewählt werden, um Welleninterferenzen zu vermeiden
  • Auch die Wellenphase der Cascades muss offset werden, damit sie nicht miteinander interferieren
    • Das System versucht dies automatisch, indem es die Startzeit jeder Cascade unterschiedlich offsettet
    • Es gibt jedoch den Caveat, dass nicht sicher ist, ob dieser Ansatz tatsächlich funktioniert

Lastverteilung bei Updates

  • Da Wellenbewegungen unregelmäßig sind, kann die Darstellung auch dann wahrnehmbar flüssig wirken, wenn Displacements nicht in jedem Frame aktualisiert werden
  • Der Parameter "update rate" steuert, wie oft pro Sekunde eine Wave Cascade aktualisiert wird
  • Das Überspringen von Frames reduziert die für FFT aufgewendete GPU-Zeit, auf Frames, in denen die Wellenerzeugungs-Pipeline läuft, kann es aber weiterhin zu Stutter kommen
  • Experimente mit asynchroner Berechnung von Cascade-Updates über Godots lokales RenderingDevice verursachten durch Texturübertragungen zwischen CPU und GPU einen großen Performance-Overhead
  • Stattdessen versucht das System eine Lastverteilung der Cascades
    • Wenn die Frame-Zeit kürzer als die update rate ist, wird pro Frame nur eine Cascade aktualisiert
    • Dieser Ansatz reduziert Stutter und erhält zugleich die Vorteile der geringeren GPU-Arbeitslast durch Frame Skipping

Referenzmaterial

1 Kommentare

 
GN⁺ 2024-09-29
Hacker-News-Meinungen
  • Zwei weitere Godot-Repositories dieser Person sind ebenfalls sehr interessant. Mir gefällt, dass sie bei der Beschreibung ihrer Repositories viele Details liefert; besonders dieses sticht hervor: https://github.com/2Retr0/GodotGaussianSplatting
    Ich frage mich, ob sie Student ist. Sie zitiert häufig andere Arbeiten und scheint kürzlich veröffentlichte Materialien ziemlich gut zu verstehen.

    • Es wirkt plausibel, dass es ein Student ist. Titel und Beschreibung eines Repositories lauten ENGR96A-coursework, Relevant coursework for ENGR 96A Introduction to Engineering Design F23, und den Commit-Daten nach scheint F23 für das Herbstsemester 2023 zu stehen.
      Natürlich könnten die im Repository erwähnten UCLA-Kurse auch öffentlich zugänglich sein; man muss also vielleicht nicht im klassischen Sinn an der UCLA eingeschrieben sein, um sie zu belegen.
  • Vor 20 Jahren hätte man wahrscheinlich monatelang an der Meeresoberfläche im Rendering gefeilt und wäre trotzdem nicht annähernd auf dieses Niveau gekommen. Wirklich ein sehr gut gemachtes Ergebnis.
    Allerdings wirkt das Demo-Video etwas überzeichnet. Aus Sicht von jemandem mit über 50.000 Seemeilen Hochseefahrt im Logbuch müssten bei so scharfen, hohen Wellen deutlich stärkere Winde wehen. Das dürfte sich aber wohl einfach über Parameter anpassen lassen.
    Wenn das in Godot gemacht ist, kann man dann von Echtzeit-Rendering ausgehen? Ich frage mich auch, ob dafür eine Monster-GPU nötig ist.

    • Nicht als Kritik, eher als Beobachtung: So sähe es wohl aus, wenn man sich ein Meer aus blau eingefärbtem heißem Maissirup vorstellt. Die Viskosität wirkt passend, aber die Oberflächenspannung dürfte sich von echtem Meerwasser unterscheiden. Echtes Meerwasser ist eine Kolloidsuppe aus salzhaltigem H2O und biologischem Material – in der Realität alltäglich, in der numerischen Strömungsmechanik aber ein ziemlich schmutziges Objekt.
      Außerdem wirkt die Gischt hier wie ein nachträglicher Effekt; in der echten See entschärft Gischt die Schärfe der Wellen, was sich auch visuell subtil zeigt.
      Natürlich steckt in diesem eleganten, einfachen und effektiven Modell kaum Physik. Daher bitte eher als Herumstochern und Vorschläge für mögliche Richtungen verstehen, nicht als Kritik mit verschränkten Armen.
    • Heutzutage gibt es viele Videos, die so etwas behandeln, dadurch ist der gesamte Prozess einigermaßen zugänglich geworden, aber es gibt immer noch viele Fallstricke.
      Eines meiner Lieblingsvideos zu diesem Thema: https://m.youtube.com/watch?v=yPfagLeUa7k
      Dieses ist auch gut: https://m.youtube.com/watch?v=kGEqaX4Y4bQ
    • Ich habe ein Game-Projekt, und jedes Mal, wenn ich coole Game-Tech sehe, werde ich nerd-gesniped und will sie selbst implementieren. Hätte ich fertige Assets benutzt oder gekauft, wäre der bisherige Fortschritt vermutlich auch in einem 48-Stunden-Game-Jam möglich gewesen.
      Stattdessen verbringe ich jedes Wochenende damit, am Wasser-Shader herumzuspielen, bis er so aussieht, wie ich es will. Mein Spiel ist allerdings ein Puzzle-Spiel und braucht gar kein Wasser. Jetzt habe ich lediglich einen schicken Startbildschirm.
    • Als ich meinen Abschluss gemacht habe, waren Dinge wie Particle Engines oder Marching Cubes noch Themen für Abschlussarbeiten.
      Heute ist das nur noch eine Checkbox in einer Game-Engine, und davon gibt es unzählige. Viele können sich gar nicht vorstellen, wie gut die Umgebung dank moderner Engines geworden ist.
      Ich will die Leistung dieser Arbeit nicht schmälern; sie ist wirklich hervorragend, und dem Entwickler gebührt Lob. Ich wollte nur sagen, in was für guten Zeiten wir inzwischen leben.
    • Ich stimme zu, dass es im Video etwas zufällig wirkt.
      Trotzdem sieht es sehr gut aus, und nach meinem jüngsten oberflächlichen Suchen gehört es vermutlich zum Besten, was derzeit möglich ist.
      Persönlich würde ich bei Hochseewellen gern mehr Rhythmus sehen. Ich frage mich, ob eine Simulation von 15 Knoten Wind, der mehrere Stunden lang über 1 km Wasseroberfläche weht, dem entspricht, was man tatsächlich beobachtet: relativ geordnete Brecher, die entstehen und sich wieder zerstreuen.
  • Solche Dinge haben mich einst in die Computerwelt gezogen, aber irgendwann bin ich in ein einfaches, langweiliges Leben geraten, in dem man Bibliotheken, Endpoints und unternehmerischen Bullshit zusammenklebt, was in Burnout mündet.
    Ich hoffe, irgendwann wieder dorthin zurückzufinden.

    • Ich denke, man kann sich schrittweise verlagern. Such dir ein Gebiet, das dich ursprünglich fasziniert hat, über das du mehr lernen und das du letztlich ausprobieren willst; vertiefe dich jede Woche ein paar Stunden darin und steigere das allmählich, während du dich von deiner aktuellen Arbeit entfernst.
      Probier es aus. Wir drücken dir alle die Daumen.
    • Ich sehe viele Freunde, die mit solcher Arbeit mehr verdienen als ich, aber ich bin meinen Interessen gefolgt und bei der ersten Gelegenheit in die Robotik gegangen. Ich bereue es nicht. Zumindest für mich gibt es kaum etwas Vergleichbares, als zu sehen, wie mein Code mit der realen Welt interagiert.
  • Der Ansatz ist anders, aber wer sich für Wellen-/Ozeansimulation interessiert: Acerola hat dazu wie immer ein hervorragendes Video gemacht. https://youtu.be/PH9q0HNBjT4 und https://youtu.be/yPfagLeUa7k
    Edit: Eines davon war in den Referenzen bereits verlinkt, aber unter dem echten Namen statt dem Nickname, daher habe ich es erst jetzt bemerkt.

  • Interessant, wie schwierig dieses Problem ist. Seit Jahrzehnten versucht man es, und trotzdem steckt es immer noch im Uncanny Valley.
    Wenn man diese Szene anhält, sehen die aufragenden Wellen wie schneebedeckte Berge aus. Damit Wasser so scharfe Formen annimmt, müsste der Wind ziemlich stark sein, aber Wind bläst nun einmal nicht direkt nach oben, daher wirkt es unrealistisch. Solche scharfen Merkmale müssten eine Richtung haben.
    Die Eigenschaften von Dünung sind aber ziemlich gut getroffen. Die Auf-und-ab-Bewegung ist größer als die horizontale Bewegung, was man auf offener See erwarten würde.

    • Ich habe Nightingale gespielt, und das Meerwasser dort ist wirklich besonders. Um es klar zu sagen: Sie halten die Wellen offenbar ruhig, sodass sie sich nicht mit Problemen wie Gischt befassen müssen, und können sich stattdessen auf andere Dinge konzentrieren.
      Ich weiß nicht, wie sie Lichtdurchlässigkeit simulieren, aber es funktioniert gut. Das Licht, das bei Sonnenauf- oder -untergang zwischen den Wellen hindurchscheint, ist großartig und macht den Effekt sehr glaubwürdig.
      Man könnte es etwas malerisch nennen, aber es sieht nicht falsch aus.
  • Ich habe mehrere Jahre am Strand gelebt. Wenn man am Strand lebt, ist das Meer faszinierend und sinnlich ansprechend, sodass man stundenlang darauf schauen kann. Bei diesem hier hätte ich keinen Moment gedacht, dass es gerendert ist.

    • Ich lebe derzeit am Strand und habe auch einen Ausblick ungefähr aus dem 14. Stock über dem Wasser; seltsamerweise ist hier klar zu sehen, dass es fake ist. Es fehlen die dunklen Flecken durch Windböen, und die weißen Bereiche steigen direkt nach oben, ohne sich auch nur leicht einzurollen. Ansonsten wirkt es ziemlich echt.
    • Hast du tatsächlich schon einmal Wellen und ihre Bewegung gesehen? Wenn du mehrere Jahre am Strand gelebt hast, solltest du sofort erkennen, dass die Schaumbildung und die Bewegung der Wellen nicht natürlich sind.
  • Auf Shadertoy gibt es ebenfalls ein gutes Beispiel: https://www.shadertoy.com/view/Ms2SD1

  • Da Fourier auf die Idee der Frequenztransformation von Wellen kam, während er Gezeitenwellen maß, schließt sich in gewisser Weise fast der Kreis.
    Sehr beeindruckend.

  • Großartig, aber dieser Ansatz wird bei wirklich großen Wellen wegen der Nichtlinearität bis zu einem gewissen Grad zusammenbrechen. Wasserwellen sind keine Sinuswellen, aber bei kleinen und mittelhohen Wellen sind sie ähnlich genug, sodass diese Methode sehr gut funktioniert.
    Sehr große Wellen weichen nicht nur viel stärker von Sinuswellen ab, sondern beginnen auch, nichtlinear miteinander zu interagieren; das kann die hier verwendete lineare Überlagerung nicht erfassen.
    Für die meisten Seegangsbedingungen ist es daher fantastisch. Wenn man aber Wellen wie in „Der Sturm“ realistisch erzeugen will, braucht man einen anderen Ansatz.

  • Sehr beeindruckend und besser als alles, was ich bisher gesehen habe, aber die Dünung wirkt etwas daneben. Wenn ich es erklären müsste: Hochfrequente Wellen bewegen sich wohl nicht so über niederfrequente Wellen hinweg, wie es im Video aussieht.