(10) Deferred Shading Vorlesung Computergrafik II Stefan Müller Dank an Niklas Henrich, Gerrit Lochmann
Wdh. 1: Framebufferobjects (FBOs) Statt in den Framebuffer direkt zu rendern, kann man Texturen attachen, in die gerendert werden soll (render to texture) Ein Framebuffer-Objekt kann mehrere Rendering-Ziele beinhalten - GL_COLOR_ATTACHMENT0 - GL_COLOR_ATTACHMENTn - GL_DEPTH_ATTACHMENT - GL_STENCIL_ATTACHMENT - Default Framebuffer wird vom Windows-Manager eingerichtet (Color, Depth und Stencil). S. Müller - 2 -
Wdh. 2: Beispiel Depthbuffer FBO generieren und binden GLuint framebufferhandle = 0; glgenframebuffers(1, &framebufferhandle); glbindframebuffer(gl_framebuffer, framebufferhandle); Texturobj anlegen + binden GLuint depthtexturehandle; glgentextures(1, &depthtexturehandle); glbindtexture(gl_texture_2d, depthtexturehandle); Textur anlegen und Parameter setzen glteximage2d( ); gltexparameteri( ); Textur an FBO attachen glframebuffertexture2d( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthtexturehandle, 0); Szene rendern gldrawbuffer(gl_none); // No color buffer is drawn to. Später darauf zugreifen glbindtexture(gl_texture_2d, depthtexturehandle); S. Müller - 3 -
Wdh. 3: Shadow Mapping Einfache Schattenabfrage pro Fragment/pro Lichtquelle vec3 p = pos_lks.xyz / pos_lks.w; float depth = texture( tex, vec2(p.x,p.y)).x; if (depth < (p.z-0.0005)) //Schatten Selbstverdeckung (Shadow Acne) GL_POLYGON_OFFSET_FILL Peter Panning (Schwebende Objekte) glcullface(gl_front) Aliasing Effekte Percentage Closer Filter (PCF) Weiche Schatten Flächige Lichtquellen Mehrere Samples/Shadowmaps S. Müller - 4 -
Deferred Shading Stefan Müller - 5 -
Deferred Shading Ein sehr unscharfer Begriff Im allgemeinen Fall versteht man darunter Deferred Shading ( verzögertes Schattieren ) oder auch Deferred Lighting ( verzögerte Beleuchtung ) Szene in verschiedene Texturen rendern In einem zweiten Schritt auf / mit dem Inhalt der Texturen arbeiten Praktisch jede moderne GPU-Anwendung benutzt irgendeine Form des deferred rendering / shading Im Folgenden wird das Szenario (Beleuchtung von Objekten in einer Szene) vorgestellt, für welches der Begriff am häufigsten verwendet wird S. Müller - 6 -
Objekte in Szene beleuchten (ohne Deferred Shading) Eine Möglichkeit Für jede Lichtquelle in der Szene Lichtquelle aktivieren Für jedes Objekt in der Szene Objekt zeichnen Jedes Objekt muss somit #Lichtquellen #Objekte mal gezeichnet (und beleuchtet) werden Manche Objekte werden beleuchtet, obwohl sie vielleicht in einem späteren Schritt von einem anderen Objekt verdeckt werden S. Müller - 7 -
Objekte in Szene beleuchten (ohne Deferred Shading) Eine andere Möglichkeit Für jedes Objekt in der Szene Für jede Lichtquelle in der Szene Lichtquelle aktivieren und Objekt zeichnen Jedes Objekt muss wieder #Lichtquellen #Objekte mal gezeichnet und beleuchtet werden Warum nicht mehrere Lichtquellen gleichzeitig anwenden? Funktioniert bei wenigen Lichtquellen Manche Anwendungen (Spiele) können über hunderte von Lichtquellen verfügen, die gleichzeitig aktiv sind Zu viele Argumente an einen Shader S. Müller - 8 -
Deferred Shading Für jedes Objekt in der Szene Rendere Weltkoordinate, Normale, Farbe etc. in MRTs Für jede Lichtquelle in der Szene Beleuchtung als Postprocess auf den erstellten Texturen Vorteile Jedes Objekt wird genau einmal gezeichnet Es werden nur die tatsächlich sichtbaren Pixel beleuchtet Aufwand: #Objekte + #Lichtquellen anstatt #Lichtquellen #Objekte S. Müller - 9 -
Was leisten folgende Shader? Vertex-Shader in vec4 In_Position; in vec2 In_UvCoord; in vec4 In_Normal; uniform mat4 u_model; uniform mat4 u_view; uniform mat4 u_projection; out vec4 Pass_Position; out vec2 Pass_UVCoord; out vec3 Pass_Normal; void main(){ Pass_UVCoord = In_UvCoord; Pass_Position = u_view * u_model * In_Position; gl_position = u_projection * u_view * u_model * In_Position; Pass_Normal = vec3(transpose(inverse(u_view * u_model))* In_Normal);} Fragment-Shader in vec4 Pass_Position; in vec2 Pass_UVCoord; in vec3 Pass_Normal; uniform sampler2d u_tex; out vec4 Out_Position; out vec4 Out_Normal; out vec4 Out_Color; void main(){ Out_Position= Pass_Position; Out_Normal= vec4(normalize( Pass_Normal), 0); Out_Color= texture(tex, Pass_UVCoord);} S. Müller - 10 -
Multiple Render Targets Der Vorteil der FBOs Multiple Render Targets (MRT) In einem Schritt in verschiedene Texturen rendern Ohne MRTs müsste die Szene für jede Information (Position, Normale, etc.) neu gerendert werden Render Target 1 (Textur) Fragment Program Position Render Target 2 (Textur) Render Target 3 (Textur) Niklas Henrich - 11 -
G-Buffer Trennung der Geometrieverarbeitung von der Lichtberechnung Im ersten Pass werden für jedes Pixel alle beleuchtungsrelevanten Daten (z.b. 3D-Position, Normale, Texturfarbe, Glanzzahl) in unterschiedliche Rendertargets (oftmals auch G-Buffer genannt) rasterisiert. Dies geschieht sogar gleichzeitig (also Füllen der Buffer in einem Schritt) 3D-Position; Normale; Farbe S. Müller - 12 -
Compositing Am Ende geht man Pixel für Pixel durch Für jedes Pixel (vorderstes Flächenelement) seht alles zur Verfügung, was man zur Beleuchtung benötigt: Position in Kamerakoordinaten Normale in Kamerakoordinaten Farbe Hierfür rendert man ein bildschirmfüllendes Rechteck (screen filling quad) Dadurch wird für jedes Pixel der Fragment-Shader aufgegriffen In diesem Pass findet die Beleuchtung pro Pixel statt S. Müller - 13 -
Screen filling Polygon y Vertex-Shader in vec2 In_Position; out vec2 Pass_UV; void main() { gl_position = vec4(positionattribute, 0, 1); passuv = (positionattribute + 1) / 2; // Texturkoordinaten zwischen 0 und 1 } Dreieck y 3 1 1 1 1 1 x 1 1 1 3 x S. Müller - 14 -
Final Composition (Fragment-Programm) in vec2 Pass_UV; uniform sampler2d positionmap; uniform sampler2d normalmap; uniform sampler2d colormap out vec4 fragmentcolor; void main() { vec4 position = texture(positionmap, passuv); vec4 normal = texture(normalmap, passuv); vec4 color = texture(colormap, passuv); //lightposition from camera system vec4 lightpos = vec4(0,4,-4,1); //calculate lighting with given position, normal and lightposition vec3 npostolight = normalize(vec3(lightpos.xyz - position.xyz)); float ambient = 0.3; float diffuse = max(dot(normal.xyz, npostolight), 0); } fragmentcolor = color * ambient + color * diffuse; S. Müller - 15 -
Ergebnis S. Müller - 16 -
Deferred Shading Kamera-/Weltkoordinate? Falls genügend Platz vorhanden ist, können die 3 Koordinaten in einer eigenen Textur gespeichert werden Ansonsten kann die Position aus dem Tiefenwert sowie der Position des Pixels im Framebuffer und der Kamera errechnet werden Trade-off: Speicherverbrauch vs. Rechenlast Anmerkung Normalen: Falls die Normalen normalisiert sind, müssen nur zwei Werte gespeichert werden Der dritte kann aus diesen errechnet werden Das Vorzeichen des dritten Wertes muss bei einem anderen Wert mit abgespeichert werden Z.B. Tiefenwert (ist immer positiv) S. Müller - 17 -
Deferred Shading performante Beleuchtung Approximiere Lichtkegel durch konvexes Polygon Aktiviere Back-Face Culling Rendere konvexes Polygon Für jedes Pixel, das durch den Lichtkegel überdeckt wird, wird der Lichtquellen- Pixel Shader aktiviert Pixel Shader liest Daten aus G-Buffer aus (Position, Normale, Material etc.) und führt Lichtberechnungen für aktuelles Pixel durch Anmerkung: Wenn kein Back-Face Culling aktiviert ist, wird jedes Pixel doppelt beleuchtet. Der Pixel Shader würde einmal für die Vorderseite und einmal für die Rückseite des Polygons aktiviert. Stefan Müller - 18 -
Deferred Shading Für die roten Pixel wird der Beleuchtungs -Pixel Shader aktiviert Stefan Müller - 19 -
Deferred Shading Pixel Shader liest an seiner Position die Informationen aus dem G-Buffer aus und führt Beleuchtungsberechnung durch Position liest Daten Normale Material Stefan Müller - 20 -
Deferred Shading Vorteile Viele Lichtquellen bei komplexer Geometrie möglich Postprocessing Effekte (Compositing) (Bloom, Tonemapping, Depth of Field, etc.) können einfach angeschlossen werden, da bereits alle benötigten Informationen aufbereitet vorliegen. Nachteile Speicherverbrauch des G- Buffers Hohe Bandbreitenausleistung (viele Texturzugriffe) Kein Antialiasing / Multisampling Wird nicht auf den Color Attachments durchgeführt Transparenzen Pro Pixel wird nur das vorderste Objekt gespeichert Stefan Müller - 21 -
Deferred Shading Demo http://www.humus.name/index.php?page=3d&id=74 Demo Stefan Müller - 22 -
Filter S. Müller - 23 -
Filter Mit Hilfe eines screen-filling Polygons lassen sich Texturen auch sehr gut filtern. Für jedes Pixel werden die entsprechenden Nachbarpixel bestimmt, gemäß der Filtermaske gewichtet und das Resultat als finale Pixelfarbe weitergegeben. Allerdings werden hier je nach Filter-Kernel ziemlich viele Texturzugriffe nötig. Ist der Filter separierbar, so lässt sich dies effizienter implementieren S. Müller - 24 -
Glow Demo Demo Finales, gerendertes Bild wird z.b. mit Gauß-Maske gefiltert und geblendet Besser: nur helle Flächen rendern/filtern (hier durch zusätzliche Textur) GPU Gems S. Müller - 25 -
Environment Maps S. Müller - 26 -
Cube Mapping Eine Form des Environment Mappings Umgebung wird durch 6 Texturen beschrieben Kamera sieht nach vorne, hinten, oben, unten, links und rechts Texturen aus Media-Ordner der DirectX SDK March 2008 Microsoft Corp. Niklas Henrich - 27 -
Environment Mapping Simulation von Objekten, die deren Umgebung reflektieren Gespiegelten oder gebrochenen Strahl als look-up in die Cube Map benutzen i n r Vertex Shader r = reflect(i, n); Fragment Shader envcolor = texturecube(envmap,r); Cube Map Niklas Henrich - 28 -
Environment Mapping - Ergebnisse Demo r = reflect(i, n) ersetzt durch r = refract(i, n, 1.1) Niklas Henrich - 29 -
Depth Peeling S. Müller - 30 -
Depth Peeling Im Framebuffer ist immer das vorderste Pixel zur Kamera zu sehen Depth Peeling erzeugt n Bilder, in denen jeweils das vorderste, zweit-vorderste,, n-vorderste Pixel zu sehen ist Stefan Müller - 31 -
Depth Peeling Ablauf 1. Schritt (Vordersten Pixel) Szene rendern Tiefenpuffer abspeichern 2. bis n.schritt ( Zweit-vordersten bis n-vordersten Pixel ) Szene rendern Im Pixel Shader den Tiefenwert des aktuellen Fragments mit dem Wert aus dem zuvor gespeicherten Tiefenpuffer vergleichen Nur diejenigen Fragments mit einem größeren Tiefenwert zeichnen Tiefenpuffer für gezeichnete Pixel speichern Stefan Müller - 32 -
Depth Peeling Bilder Ebene 0 Ebene 1 Demo Ebene 2 Ebene 3 Stefan Müller - 33 -
Depth Peeling Komplexität ist linear O(n) Größter Kritikpunkt Speicherverbrauch ist linear Ein Bild pro Schicht Komplexe Szenen bestehen schnell aus 20+ Schichten Anwendungen Transparenzen Ray-Tracing Volumen Rendering Unzählige mehr Stefan Müller - 34 -
Depth Peeling - Transparenzen Um Transparenzen korrekt darstellen zu können, müssen die Objekte in der richtigen Reihenfolge gezeichnet werden Mit Depth Peeling kann dieses Problem umgangen werden Ablauf Szene depth peelen und jede Schicht (RGBA) in Textur speichern Alpha Blending aktivieren Schichten von hinten nach vorne überlagern Mit Depth Peeling (korrekte Transparenz) Ohne Depth Peeling (inkorrekte Transparenz)) Stefan Müller - 35 -
Order Independent Transparency - Demo http://developer.download.nvidia.com/sdk/10.5/opengl/samples.html#dual_depth_peeling http://developer.download.nvidia.com/sdk/10.5/opengl/src/dual_depth_peeling/doc/dualdepthpeeling.pdf Demo
Geometry-Shader Stefan Müller - 37 -
Geometry Shader Neue programmierbare Einheit der Grafikpipeline Direkt nach Vertex Shader (vor Clipping etc.) Dynamisch neue Geometrie erzeugen Geometrie löschen Stefan Müller - 38 -
Geometry Shader - Eingabe Arbeitet immer auf gesamten Eingabeprimitiv Mögliche Eingabeprimitive Punkt Linie Dreieck Shader hat Zugriff auf Alle Punkte des Eingabeprimitives Alle direkt benachbarten Punkte Zugriff möglich q2 p2 q1 p1 Benachbartes Dreieck p0 q0 Stefan Müller - 39 -
Geometry Shader - Ausgabe Ausgabe (beliebig* viele) Punkte Linien (line strips) Dreiecke (triangle strips) Es ist auch möglich, keine Geometrie auszugeben Maximale Anzahl der ausgegebenen Primitive pro Shaderaufruf muss zur Compile-Zeit bekannt sein Je größer diese Zahl, umso stärker sinkt die Performance Ein- und Ausgabetyp können verschieden sein Dreieck als Eingabe Linienzug als Ausgabe Wireframe *beliebig bedeutet bis zum Hardwarelimit Stefan Müller - 40 -
Geometry Shader neue Befehle EmitVertex() Eckpunkt dem aktuellen Ausgabeprimitiv (z.b. Dreieck) hinzufügen gl_position = vec4(1.0, 0.5, 0.3, 1.0); EmitVertex(); EndPrimitive() Aktuelles Ausgabeprimitiv abschließen Neues Ausgabeprimitiv vom gleichen Typ wird begonnen Ähnlich wie OpenGL-Befehlsreihenfolge: glend(); glbegin( ); Stefan Müller - 41 -
Beispiel aus Eins mach Drei Geometry Shader: Aus Geometry Shader: Ein Stefan Müller - 42 -
Beispiel aus Eins mach Drei void main() { // 1. Dreieck erzeugen und verschieben for(int i = 0; i < gl_verticesin; i++){ gl_frontcolor = vec4(0,1,0,1); gl_position = vec4(gl_positionin[i].x * 0.5, (gl_positionin[i].y * 0.5) + 0.5, 0, 1); EmitVertex(); } EndPrimitive(); // 2. Dreieck erzeugen und verschieben // 3. Dreieck erzeugen und verschieben. Anzahl der Eckpunkte des Eingabeprimitives Array von Eckpunkten des Eingabeprimitives Stefan Müller - 43 -
Geometry Shader Ausgabelimit Ein Geometry Shader kann momentan maximal ca. 256 Eckpunkte ausgeben Soll mehr Geometrie erzeugt werden, muss dies in mehreren Schritten geschehen Folgende Funktionalität wird dazu benötigt: Bereits erzeugte Geometrie muss zwischengespeichert werden können Erzeugte Geometrie muss wieder abgerufen werden können Diese Funktionalität wird durch das sogenannte Transform Feedback bereitgestellt Stefan Müller - 44 -
Transform Feedback Ermöglicht es, Geometrie in Buffer-Objekte zu rendern Fragment Shader wird ausgeschaltet Geometrie kann somit zwischengespeichert werden Inhalt des Buffers kann zu einem späteren Zeitpunkt erneut gerendert werden Stefan Müller - 45 -
Transform Feedback Vertex Shader und Geometry Shader können Geometrie beliebig verändern Neue Geometrie hinzufügen (GS) Vorhandene Geometrie verschieben (VS + GS) Geometrie löschen (GS) Nachdem gewünschte Geometrie erzeugt wurde Fragment Shader einschalten Geometrie rendern Stefan Müller - 46 -
Transform Feedback Demo http://developer.download.nvidia.com/sdk/10.5/opengl/samples.html#transform_feedback_fractal Demo Demo Stefan Müller - 47 -