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.
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:
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 (z
point - 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 :).
quelle