Wie kann ich die Grafik-Pipeline verwenden, um Volumendaten basierend auf einer Dichtefunktion zu rendern?

12

Beide Grafik-APIs (OpenGL und DirectX) entwickeln eine klar definierte Pipeline, in der mehrere Stufen programmierbar sind. Diese programmierbaren Stufen erfordern eine feste Mindestmenge an Daten und sollen einen genau definierten Bereich von Operationen ausführen und eine definierte Mindestausgabe ausgeben, damit die Daten korrekt an die nächste Stufe weitergeleitet werden können. Es scheint, als ob diese Pipelines nur für eine begrenzte Anzahl von Geometriedatentypen ausgelegt sind, bei denen es sich sowohl bei D3D als auch bei OGL um Scheitelpunktdaten und Texturkoordinaten handelt.

Wenn jedoch ein Fall vorliegt, in dem die von mir geplante Anwendung keine Eckpunkte (oder sogar Voxel) zur Darstellung ihrer geometrischen Daten verwendet und keine Transformationen oder Projektionen, keine Rasterisierung oder Interpolation oder ähnliches ausführt, gelten diese Einschränkungen für die APIs oder die Pipeline erschweren die Dinge.

Gibt es also eine Möglichkeit, die Grafik-Pipeline so zu ändern, dass die Funktionalität der einzelnen Schritte für die Daten und der in den einzelnen Schritten ausgegebenen Datentypen zu meinem Vorteil geändert wird? Wenn nicht, gibt es dann eine Möglichkeit, wie ich die 'raw'-API-Funktionen verwenden kann, um meine eigene Pipeline zu erstellen? Wenn nicht, geben Sie bitte an, warum dies nicht möglich ist.

BEARBEITEN : Meine Anwendung verwendet Dichtefunktionen zur Darstellung der Geometrie. Die Funktion hat an jedem Punkt im Raum einen Wert. Ich teile den Kegelstumpf der Kamera in ein 3D-Raster, wobei jeder Block als Pixel projiziert werden kann. In jeden Block integriere ich die Dichtefunktion und überprüfe, ob sein Wert mehr als ein erforderlicher Wert ist. Wenn ja, wird angenommen, dass in diesem Block etwas vorhanden ist und das diesem Block entsprechende Pixel gerendert wird. Jetzt möchte ich in meinem Renderer die Funktion (die ich mit einer Zeichenfolge darstelle) an die Grafikhardware übergeben, anstatt Vertexdaten in Vertexpuffern. Dies bedeutet auch, dass der Scheitelpunkt-Shader keine Scheitelpunkte zum Umwandeln in einen homogenen Clip-Raum hat und der Fragment-Shader keine Pixel-Informationen erhält. Stattdessen erfolgt das Nachschlagen und Auswerten jetzt größtenteils pro Pixel.

Der Lichtfunke
quelle
Ist 'Funktionsdichtefunktion' eine Tautologie?
Pharap
@Pharap, das war ein Tippfehler. Es ist einfach eine "Desity-Funktion", die die Anwesenheit von "Materie" im Raum repräsentiert.
The Light Spark
2
Es hört sich so an, als ob Sie nur eine Isofläche erstellen möchten, was ein gut untersuchtes Problem ist. Haben Sie http.developer.nvidia.com/GPUGems3/gpugems3_ch07.html gesehen oder nach Metaballs, Punktwolkenvisualisierung, Isoflächenextraktion oder Volumenrendering gesucht? Welche Art von Leistung Sie benötigen, wird in Kombination mit der Komplexität Ihrer Berechnungen einen großen Unterschied bei der Auswahl der gesuchten Technik ausmachen. Ich denke, dass Sie auch feststellen werden, dass pro Pixel ein Schimmern auftritt, wenn sich die Kamera bewegt, und dass Subpixel erforderlich sind.
Patrick Hughes

Antworten:

18

Sie können die GPU absolut zum Rendern von Volumendaten verwenden.

Da Sie eine Reihe von Funktionen pro Pixel auf dem Bildschirm auswerten möchten, besteht ein einfacher Ansatz darin, ein Vollbild-Dreieck zu rendern. Dies ist nur ein einzelnes Dreieck, das den gesamten Bildschirm abdeckt (tatsächlich ist es mehr als der Bildschirm, da der Bildschirm nicht dreieckig ist, sondern die Teile außerhalb des Bildschirms von der GPU verworfen werden). Sie können dann den Pixel-Shader (der die Bildschirmkoordinaten des schattierten Pixels empfängt) verwenden, um einen Strahl durch Ihr Volumen zu konstruieren, Funktionen auszuwerten und was auch immer Sie tun müssen.

(Im Gegensatz zu den anderen Antworten empfehle ich keinen Compute-Shader, da Sie anscheinend Operationen pro Pixel ausführen möchten. Ein Vollbild-Shader mit Dreiecken und Pixeln ist in der Regel effizienter als ein Compute-Shader.) Compute Shader werden sicherlich auch funktionieren.)

Die Vollbild-Dreiecksmethode ist in Echtzeit-Grafiken für Nachbearbeitungsvorgänge sehr verbreitet, sodass Sie wahrscheinlich alle Informationen, die Sie benötigen, mit ein wenig Google finden können.

Übrigens könnte es Sie interessieren, Rendering Worlds with Two Triangles von Iñigo Quílez zu lesen , ein Vortrag, der beschreibt, wie Sie mit mathematischen Funktionen (insbesondere Distanzfeldern) zusammengesetzte 3D-Szenen mit der Vollbild-Pixel-Shader-Technik rendern.

Nathan Reed
quelle
Nimmt der Pixel-Shader also beliebige Eingaben (wie Zeichenfolgen oder andere Arten von benutzerdefinierten Objekten) auf, damit ich meine Funktionen übergeben kann?
The Light Spark
Ich bezweifle, dass Sie versuchen möchten, einen Parser und / oder eine Sprache für beliebige Funktionszeichenfolgen auf der GPU auszuführen, was umständlich wäre, da GPUs nicht wirklich für allgemeine Zwecke geeignet sind. Höchstwahrscheinlich möchten Sie den Shader selbst dynamisch in Ihrem Hauptcode erstellen und dann das Grafiksystem den resultierenden Shader kompilieren und ausführen lassen.
Patrick Hughes
@TheLightSpark Richtig, Sie würden keine Strings an den Shader übergeben (Shading-Sprachen haben nicht einmal einen String-Typ). Sie möchten Shader-Code für Ihre gewünschten Funktionen generieren und kompilieren. Dies kann bei Bedarf zur Laufzeit erfolgen.
Nathan Reed
Nachdem ich Ihre Antwort gelesen hatte, stellte ich mir einen dreieckigen Monitor vor. Hat es den Vorteil, nur ein einziges Dreieck anstelle von zwei zu verwenden, die den Bildschirm abdecken, ohne Pixel zu verwerfen?
Danijar
@danijar Ja, es hat einen kleinen Vorteil gegenüber der Verwendung eines Quad-Bildschirms, da einige Pixel entlang der Diagonale bei Verwendung eines Quad-Bildschirms zweimal schattiert werden. Auf der anderen Seite ist das Verwerfen von Pixeln außerhalb des Bildschirms kostenlos, da der Rasterizer diese Pixel zunächst nicht generiert.
Nathan Reed
6

Raytracing und andere Techniken werden üblicherweise mit Compute-Shadern ausgeführt, die Direct3D seit der Veröffentlichung von D3D11 und OpenGL seit 4.3 unterstützt (und länger durch die Verwendung von OpenCL und einigen Verzerrungen).

Sean Middleditch
quelle
5

Es hört sich sehr danach an, als ob Sie einen GPU-Compute-Shader verwenden oder ein "Shader Storage Buffer" -Objekt verwenden möchten, um die Pipeline an Ihre Anforderungen anzupassen. Mathematiker, Wissenschaftler und andere Leute, die auf die GPU schauen, um Berechnungen für Dinge durchzuführen, die sich nicht genau in Standardgrafiken umsetzen lassen, verwenden diese Art von Dingen.

Obwohl die moderne Grafikpipeline sehr flexibel ist, stoßen Entwickler immer noch auf einige Einschränkungen. Die Compute-Shader-Funktion erleichtert es uns jedoch, nicht an Pipeline-Phasen zu denken, da wir es gewohnt sind, an Scheitelpunkte und Fragmente zu denken. Wir sind nicht länger auf die Ein- und Ausgänge bestimmter Pipelinestufen beschränkt. So wurde zum Beispiel die Funktion Shader Storage Buffer Object (SSBO) zusammen mit Compute-Shadern eingeführt, die zusätzliche Möglichkeiten für den Datenaustausch zwischen Pipeline-Stufen sowie eine flexible Ein- und Ausgabe für Compute-Shader bietet.

http://community.arm.com/groups/arm-mali-graphics/blog/2014/04/17/get-started-with-compute-shaders

Wenn dies nicht in die richtige Richtung weist, würde es Ihnen etwas ausmachen, Ihr Konzept zu erweitern, das nicht zum Vertex- / Fragment-Paradigma passt?

AAorris
quelle
Ich habe meine Antwort so bearbeitet, dass sie das, was ich tue, enthält. Der Compute-Shader scheint die Antwort zu sein, aber sag mir einfach, ob ich noch etwas anderes tun kann.
Der