Wie wird Signed Distance Field Ray Marching für eine dynamische Welt implementiert?

10

Ich glaube, ich verstehe die Grundlagen des Signed Distance Field Ray Marching. Sie modellieren Ihre Szene mit einer Reihe von Entfernungsfeldern (z. B. http://iquilezles.org/www/articles/distfunctions/distfunctions.htm ) und beginnen dann für jedes Pixel, das Sie einen Strahl werfen, am Anfang des Strahls Suchen Sie die Entfernung zum nächsten Objekt an diesem Punkt und erhöhen Sie den Punkt um die nächste Entfernung, bis Sie auf etwas treffen. Ich habe es geschafft, einen einfachen Renderer zu erstellen, und hier hören die meisten Beschreibungen der Technik auf.

Dies lässt mich einige Fragen offen, wie SDF Ray Marching in einem realen Szenario verwendet werden kann:

Frage 1: In einem echten Spiel ist die Szene normalerweise komplex und mit vielen dynamischen Objekten auf der CPU geladen. Ich verstehe das grundlegende Okklusions-Culling (z. B. Octrees) und beim polygonalen Rendern würde ich eine Liste (auf der CPU) von Elementen in der Ansicht erstellen, die frustriert zu rendern sind.

Stellen Sie sich vor, ich habe eine sehr komplexe Szene mit vielen Charakteren und dynamischen Objekten, die sich auf dem Bildschirm bewegen und von der CPU gesteuert werden. Wie würde ich die Objekte, die ich rendern möchte, in jedem Frame auf die GPU streamen? In jedem Beispiel ist die Szene in GLSL fest codiert. Kann jemand ein Beispiel für die Ebene teilen, die dynamisch an den Shader gestreamt wird?

Frage 2: Wie können Objekte mehrere Farben haben? Die Distanzfunktionen geben nur eine Distanz zurück, aber wie geben Implementierungen die Farbe normalerweise zurück? (zB Sie treffen eine rote Kugel und keinen blauen Würfel.) Wenn dies eine CPU-Implementierung wäre, könnte ich eine globale Funktion innerhalb der Distanzfunktion aufrufen, wenn es ein Treffer ist, um den Ray Marcher zu beenden, und das könnte auch die des getroffenen Objekts passieren Textur / Farbe. Aber wie würden Sie die Farbe oder Textur des Artikels in GLSL zurückgeben?

Vielen Dank.

Andrew Price
quelle

Antworten:

2

Dies ist eine minimale Antwort, wollte aber die Informationen teilen, falls Sie keine bessere Antwort erhalten haben.

In Bezug darauf, wie echte Spiele Ray Marching verwenden, tun sie dies normalerweise nicht. Erst in den letzten Jahren haben Spiele damit begonnen, den Tiefenpuffer zu strahlen, um Reflexionen auf dem Bildschirm zu machen, aber kein Spiel, von dem ich weiß, dass es das Marschieren so verwendet, wie Sie es beschreiben - noch?

Bei der anderen Frage zu Farben und dergleichen assoziieren Menschen häufig Materialien mit Objekten und verwenden "Texturkoordinaten" des Punktes, an dem der Strahl auf das Objekt trifft, um die Materialeigenschaften an diesem Punkt des Objekts herauszufinden. Übliche Materialien sind Dinge wie diffuse Farbe, Spiegelintensität, Emissionsfarbe und Transparenz / Brechungsindex.

Hoffe das ist wenigstens etwas Hilfe für dich! Möglicherweise erhalten Sie auch gute Antworten von der Website zum Austausch von Grafikstapeln.

Alan Wolfe
quelle
2
"Kein Spiel, von dem ich weiß, dass es Ray Marching so verwendet, wie Sie es beschreiben." Media Molecules bevorstehendes Spiel Dreams verwendet signierte Distanzfelder für die benutzergenerierte Inhaltsformung. Wenn ich das richtig verstehe, werden die Felder zum Rendern in eine Punktwolke konvertiert direkt gestrahlt werden. Dieser Artikel kann einige Ideen haben: dualshockers.com/2015/08/15/…
DMGregory
1
@ DMGregory Schön, aber ich denke, das ist nicht ausschließlich Ray Marching. Der Punkt ist also immer noch gültig, Spiele verwenden normalerweise kein Ray Marching.
Konzept3d
1
Aktualisieren dieses Threads - Das kommende Spiel Claybook rendert seine Szenen Berichten zufolge mit Strahlen, die direkt durch Entfernungsfelder abgefeuert werden , anstatt sie zuerst in herkömmliche Geometrie umzuwandeln. Also das "noch?" scheint zwei Jahre später bestätigt worden zu sein. :)
DMGregory
1

Ich entwickle derzeit eine Spiel-Engine, die signierte Distanzfelder als Rendering-Technik verwendet, um eine reibungslose prozedurale Geometrie anzuzeigen (generiert mit einfachen Grundelementen wie den in Ihrem Link, um in Zukunft Julia- und IFS-Fraktale zu implementieren). Da meine Engine auf die prozedurale Generierung ausgerichtet ist und Zahlen so definieren muss , dass sie ray-marcher-freundlich sind, bin ich an einem guten Ort, um diese Frage zu beantworten: P.

In Bezug auf Streaming besteht die einfache Lösung darin, einen typisierten Puffer zu verwenden und ihn auf die GPU zu werfen, wenn Sie Ihren Ray-Marsch durchführen möchten. Jedes Element des Puffers ist ein komplexer Typ (z. B. eine Struktur in C / C ++), und jeder Typ enthält Elemente, die definieren, welche Funktion Sie zur Darstellung verwenden sollen, Position, Drehung, Skalierung usw. und eine durchschnittliche Farbe. Der Prozess vereinfacht sich dann auf:

  1. Wählen Sie Ihre Szene in eine überschaubare Teilmenge aus (beachten Sie, dass das Keulen von Kegelstumpf und das Keulen von Okklusionen teilweise sowieso automatisch vom Ray-Marching-Algorithmus ausgeführt werden).
  2. Übergeben Sie die Teilmenge in Ihren Render-Eingabepuffer
  3. Übergeben Sie den Puffer an die GPU, falls er noch nicht vorhanden ist, und rendern Sie Ihre Szene mit herkömmlichem Ray-Marching. Sie müssen eine Art pro-Schritt-Suche durchführen, um zu bewerten, welches Element im Eingabepuffer für jede Iteration des Ray-Marchers jedem Strahl am nächsten ist, und Sie müssen Transformationen auf beide Strahlen anwenden (in diesem Fall) Sie müssen die Figurendrehungen invertieren, bevor sie die GPU erreichen) oder die Distanzfunktionen selbst (Verschieben des Funktionsursprungs für Positionsänderungen, Anpassen von z. B. kubischen Seitenlängen für Skalenänderungen usw.). Der einfachste Ansatz besteht darin, die Strahlen vorher zu ändern Sie geben sie an die eigentliche Kerndistanzfunktion weiter.

Denken Sie in Bezug auf Figurenfarben daran, dass Sie mit Shadern sowohl komplexe Typen als auch Grundelemente definieren können;). Auf diese Weise können Sie alles in eine Struktur im C-Stil werfen und diese Strukturen dann von Ihrer Distanzfunktion zurückgeben.

In meiner Engine enthält jede Struktur einen Abstand, eine Farbe und eine ID, die sie mit der entsprechenden Figurendefinition im Eingabepuffer verknüpft. Jede ID wird aus dem umgebenden Kontext der relevanten Distanzfunktion abgeleitet (da meine Zuordnungsfunktion den Eingangspuffer durchläuft, um für jeden Schritt die nächstgelegene Zahl zu jedem Strahl zu finden, kann ich den Wert des Schleifenzählers sicher behandeln, wenn jede SDF aufgerufen wird als die Figuren-ID für diese Funktion), während Abstandswerte unter Verwendung einer beliebigen Kern-SDF definiert werden (zpoint - figure.pos für eine Kugel), und Farben werden entweder aus der Durchschnittsfarbe des entsprechenden Elements im Figurenpuffer definiert (daher ist es nützlich, die Figuren-IDs beizubehalten) oder durch eine prozedurale Farbe, die in Richtung des gespeicherten Durchschnitts gewichtet ist (ein Beispiel könnte sein eine Iterationszahl für einen bestimmten Punkt auf der Mandelbulb, wobei Ihre "durchschnittliche Farbe" vom FP-Farbraum auf den ganzzahligen Farbraum abgebildet wird und dann die zugeordnete Farbe als Palette verwendet wird, indem sie mit der Iterationszahl XOR-verknüpft wird).

Prozedurale Texturen sind ein anderer Ansatz, aber ich habe sie selbst nie verwendet. iq hat in diesem Bereich viel recherchiert und einige interessante Demonstrationen auf Shadertoy veröffentlicht, so dass dies eine Möglichkeit sein könnte, zusätzliche Informationen zu sammeln.

Unabhängig davon, ob Ihre Farbe für jede Figur statisch ist, prozedural generiert oder magisch aus einer prozeduralen Textur abgetastet wurde, ist die Grundlogik dieselbe: Abstrakte Figuren in einer Art komplexem Zwischentyp (z. B. einer Struktur) speichern sowohl lokale Distanz als auch lokale Farbe in einer Instanz dieses Typs, dann übergeben Sie den komplexen Typ als Rückgabewert von Ihrer Distanzfunktion. Abhängig von Ihrer Implementierung kann die Ausgabefarbe dann direkt auf den Bildschirm übertragen werden oder dem Kollisionspunkt in Ihren Beleuchtungscode folgen.

Ich weiß nicht, ob das oben Genannte klar genug war oder nicht, also mach dir keine Sorgen, ob irgendetwas keinen Sinn ergibt. Ich kann keine GLSL / Pixel-Shading-Codebeispiele geben, da ich mit HLSL arbeite und Shading berechne, aber ich versuche gerne, alles durchzugehen, was ich überhaupt nicht richtig geschrieben habe :).

Paul Ferris
quelle