Mehrere Shader verwenden

53

Ich studiere gerade Opengl-Shader, aber ich kann nichts herausfinden: wie man unterschiedliche Shader auf die Objekte anwendet, zum Beispiel eine Teekanne, die mit Toon-Shader gerendert wurde, und eine andere in derselben Szene, die eine stark reflektierende Oberfläche verwendet und von der andere verzerrt ist eine Rauschfunktion, wie in diesem Video

http://www.youtube.com/watch?v=1ogg4ZfdBqU

Eine andere Methode wendet einen Bloom-Shader in einer Szene und anschließend einen Motion-Blur-Shader an. Wie können Sie diese Effekte erzielen, wenn Sie nur einen Vertex-Shader und einen Fragment-Shader haben können? Gibt es einen Trick wie die Verwendung von mehr als einem Shader-Programm?

ibrabeicker
quelle
Bezüglich der guten Antworten von Nathan und David sehen Sie daher den Begriff Render-Pass oder Shader-Pass . Es sind mehrere Durchgänge erforderlich, um das endgültige Bild / Bild zu erstellen. Einer der Gründe, warum die GPU-Verarbeitung so verdammt parallel und damit so schnell geworden ist, ist der Bedarf an mehreren Durchläufen pro Frame. Kehren Sie zu den Renderern der Quake II- oder Half Life-Software zurück, um sich daran zu erinnern, wie viel Liebe Shader-Pässe zur gesamten 3D-Grafikerfahrung beitragen.
Ingenieur

Antworten:

59

Die einfache Antwort ist, dass Sie sie zwischen jedem Draw-Aufruf ändern. Setze einen Shader, zeichne eine Teekanne, setze einen anderen Shader, zeichne eine andere Teekanne.

Für komplexere Aufgaben, bei denen Sie mehrere Shader auf nur ein Objekt anwenden müssen, z. B. Weichzeichnen, Glühen usw. Sie haben im Grunde alles auf Textur (en) gerendert. Dann rendern Sie ein Quad mit dieser Textur über den gesamten Bildschirm, während Sie einen anderen Shader verwenden.

Wenn Sie beispielsweise einen Glüheffekt rendern möchten, müssen Sie zuerst Ihre normale, nicht glühende Szene rendern und dann nur die farbige Silhouette des Materials rendern, das Sie auf einer Textur glühen möchten. Dann wechseln Sie zu einem Unschärfenshader und rendern Ihre Quad mit dieser Textur über Ihrer nicht leuchtenden Szene.

Es gibt eine andere Technik namens " Verschobene Schattierung", bei der Sie die Szene ohne Beleuchtung rendern und später im Bildschirmbereich anwenden. Das Hauptziel ist es, die Kosten für die Beleuchtung pro Pixel zu senken.

Normalerweise rendern Sie einen Farbpuffer, der auf dem Bildschirm angezeigt wird. Bei verzögerter Schattierung rendern Sie stattdessen einen Farbpuffer sowie einen Normal- und einen Tiefenpuffer in einem Shader-Durchgang (Sie können die normalen Vektoren und die Tiefe in einer Textur wie bei der Normal- und Höhenzuordnung speichern).

Dies bedeutet, dass Sie für jedes Pixel die Position des nächsten Teils der nicht transparenten Geometrie (Tiefe oder Abstand vom Auge), die Farbe und die Normale kennen. Aus diesem Grund können Sie die Beleuchtung auf jedes Pixel auf dem Bildschirm anwenden, anstatt auf jedes sichtbare Pixel jedes Objekts, das Sie rendern. Denken Sie daran, dass ein Objekt über andere Objekte gezogen wird, wenn die Szene nicht in der Reihenfolge von vorne nach hinten perfekt gerendert ist.

Für Schatten rendern Sie tatsächlich nur den Tiefenpuffer aus der Sicht Ihres Lichts und verwenden dann diese Tiefeninformationen, um herauszufinden, wo das Licht einfällt. Das nennt man Shadow Mapping (es gibt auch einen anderen Ansatz namens Shadow Volumes, bei dem eine Silhouette der Geometrie berechnet und extrudiert wird, Sie werden jedoch weiterhin Shader verwenden.).

Mit modernerem OpenGL (3.0+) verwenden Sie ein Framebuffer-Objekt mit angehängten Renderbuffers-Objekten. Da Renderbuffer wie eine Textur behandelt werden können. Sie können beispielsweise 1 Shader-Rendering auf mehrere verschiedene Renderbuffer anwenden (Sie müssen also nicht Ihre Textur und dann Ihre Normalen und dann die Glühkomponenten rendern ), aber die zugrunde liegende Vorgehensweise ist immer noch dieselbe.

Es ist auch wünschenswert, die Anzahl der Shader-Switches so gering wie möglich zu halten, um Overhead zu sparen. Einige Motoren gruppieren also alles mit demselben Material, sodass alle gleichzeitig gezeichnet werden können.

David C. Bishop
quelle
16

Sie binden nur einen Shader, rendern alle Objekte mit diesem Shader und binden dann den nächsten Shader, rendern die Objekte mit diesem Shader usw.

Sie können beliebig viele Shader-Objekte (Shader, die in den Speicher geladen und kompiliert werden) haben. es kann immer nur einer gebunden (aktiv) sein.

Nathan Reed
quelle
5
In Bezug auf die Implementierung verwende ich in jedem Frame glUseProgram (1) und glUseProgram (2), um die Shader zu ändern? Wie teuer ist das für die Leistung?
Ibrabeicker
4
Es sind keine trivialen Kosten (obwohl sie bei neueren GPUs geringer sind als bei früheren). Deshalb sortieren die meisten Menschen ihre Objekte nach Material und rendern alle Objekte mit demselben Material zusammen. Aber Sie können es sich durchaus leisten, die Programme zehn- bis hundertmal pro Frame zu ändern, wenn nicht sogar öfter.
Nathan Reed
9

Die Verwendung von mehr als einem Shader in einer Szene ist recht einfach. Ändern Sie den Shader, legen Sie die Werte dafür fest und rendern Sie das Objekt.

Beachten Sie jedoch, dass das Wechseln von Shadern teuer sein kann. Daher sollte das Wechseln von Shadern auf ein Minimum beschränkt werden. Es gibt verschiedene Möglichkeiten, um diese Auswirkungen zu verringern und gleichzeitig alle gewünschten Effekte zu erzielen.

Die erste und in der Regel wünschenswerteste Methode besteht darin, die Funktionalität für alle Ihre Shader-Techniken nur einem Shader hinzuzufügen und die festgelegten Bedingungen zu verwenden, um jedes Objekt auf unterschiedliche Weise mit demselben Shader zu rendern. Ich kenne OpenGL- und GLSL-Shader nicht, aber bei HLSL-Shadern und DirectX können diese als "Technik" zusammengefasst werden, und Sie können die Technik festlegen, anstatt den Shader zu ändern. Auf diese Weise können Sie tatsächlich mehrere verschiedene Pixel- und Vertex-Shader in derselben Datei haben.

Die zweite Möglichkeit, die Auswirkungen auf die Leistung zu verringern, besteht darin, den Shader festzulegen, jedes Objekt, das diesen Shader verwendet, zu rendern und dann zu wiederholen. Mit anderen Worten: Stapeln Ihres Renderings.

Wenn Sie zwei verschiedene Effekte auf dasselbe Objekt anwenden möchten (z. B. einen Toon-Shader und etwas Beleuchtung), können Sie dies auf zwei verschiedene Arten tun. Der erste besteht darin, einen Shader zu schreiben, der mehrere Effekte in derselben Funktion anwendet. Die zweite Möglichkeit besteht darin, das Modell mit jedem Shader einmal zu rendern und die Ergebnisse zu mischen, indem Sie verschiedene Mischoptionen festlegen. Dies ist jedoch viel mehr Arbeit und nicht unter allen Umständen erreichbar. Daher ist die beste Option, alle Ihre Effekte in einem Shader zu kombinieren.

OriginalDaemon
quelle
7

Eine andere Möglichkeit, die ich entdeckt habe, sind sogenannte glsl-Subroutinen, in denen jeder Shadertyp in einer Funktion definiert ist. In der OpenGL-Anwendung können wir die aktuelle Subroutine definieren, den Scheitelpunkt eines Puffers zeichnen, die Subroutine ändern und Rendern eines anderen Puffers

ibrabeicker
quelle
4
Dies erfordert GL 4.x-fähige Hardware, also Hardware der DX11-Klasse.
Nicol Bolas