Volumetrische Stencilschatten: Unterschied zwischen den Versionen
Flo (Diskussion | Beiträge) K () |
K (Verbesserungen durch zweiseitigen Stenciltest) |
||
(18 dazwischenliegende Versionen von 8 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
+ | {{Excellent}} | ||
== Konzept == | == Konzept == | ||
Bei dieser Technik nutzt man den (seit ~2000 von fast allen Grafikkarten angebotenen) [[Schablonenpuffer|Stencilpuffer]] um dort die im Schatten liegenden Bereiche der Szene abzulegen. Später werden dann mit einem passenden Stencilvergleich die Schatten dargestellt. | Bei dieser Technik nutzt man den (seit ~2000 von fast allen Grafikkarten angebotenen) [[Schablonenpuffer|Stencilpuffer]] um dort die im Schatten liegenden Bereiche der Szene abzulegen. Später werden dann mit einem passenden Stencilvergleich die Schatten dargestellt. | ||
− | Dazu wird für jedes Objekt ausgehend von seiner Silhouette (es entsteht immer dort eine Silhouetten-Kante, wo ein dem Licht abgewandtes und ein dem Licht zugewandtes Dreieck sich treffen) durch | + | Dazu wird für jedes Objekt ausgehend von seiner [[Silhouette]] (es entsteht immer dort eine Silhouetten-Kante, wo ein dem Licht abgewandtes und ein dem Licht zugewandtes Dreieck sich treffen) durch extrudieren ihrer Eckpunkte (im Idealfall in die Unendlichkeit, am einfachsten lösbar über die W-Koordinate) ein Volumen erstellt das den Bereich des Objektes darstellt den es schattiert. |
== Geschichte == | == Geschichte == | ||
Zeile 26: | Zeile 27: | ||
== Zukunft == | == Zukunft == | ||
− | Zumindest für die in der Spieleindustrie treibenden ''"Kraft"'' in Sachen OpenGL, John Carmack, gehört die Zukunft klar den Schatten Volumen. Zumal die zwei | + | Zumindest für die in der Spieleindustrie treibenden ''"Kraft"'' in Sachen OpenGL, John Carmack ([http://www.idsoftware.com/ id Software]), gehört die Zukunft klar den Schatten Volumen. Zumal die zwei frappierendsten aktuellen Nachteile (Ermitteln der [[Silhouette]] und Extrudieren eben dieser für das Volumen, sowie die hohe Anforderung an die Füllrate) dank schneller werdender Grafikkarten und CPUs immer weiter in den Hintergrund rücken. So kann man inzwischen dank [[Vertexprogramm]]en alle Eckpunkte der Silhouette einfach auf der GPU extrudieren. |
− | Auch die Tatsache dass diese Technik nur sehr scharfkantige Schatten | + | Auch die Tatsache, dass diese Technik nur sehr scharfkantige Schatten wirft, lässt sich via [[Jittering]] (mehrfachem, versetzem Rendern der Schattenvolumen mit unterschiedlicher Helligkeit) spätestens dann realisieren, wenn Grafikkarten genug Füllrate anbieten, und eben genau diese steigt von Generation zu Generation recht stetig an. |
== Grundlegende Funktionsweise == | == Grundlegende Funktionsweise == | ||
Zeile 33: | Zeile 34: | ||
Um eine Szene mit volumetrischen Stencilschatten zu rendern sieht der Renderablauf im Normalfall wie folgt aus : | Um eine Szene mit volumetrischen Stencilschatten zu rendern sieht der Renderablauf im Normalfall wie folgt aus : | ||
# Szene nur mit ambientem Lichtanteil in den Farbpuffer rendern | # Szene nur mit ambientem Lichtanteil in den Farbpuffer rendern | ||
− | # Silhouette zwischen Objekten und Lichtquellen errechnen | + | # [[Silhouette]] zwischen Objekten und Lichtquellen errechnen |
− | # Silhouetten | + | # Silhouetten extrudieren (und je nach Technik noch Deckel für das Volumen erstellen) |
# Stenciltest aktivieren und erstellte Schattenvolumen dort hinein rendern (mit unterschiedlichen Stenciloperationen für Vorder- und Rückseite) | # Stenciltest aktivieren und erstellte Schattenvolumen dort hinein rendern (mit unterschiedlichen Stenciloperationen für Vorder- und Rückseite) | ||
# Szene mit diffusem Lichtanteil rendern (da Schatten im Stencilpuffer liegen wird die Szene jetzt schattiert) | # Szene mit diffusem Lichtanteil rendern (da Schatten im Stencilpuffer liegen wird die Szene jetzt schattiert) | ||
Zeile 49: | Zeile 50: | ||
glCullFace(GL_FRONT); | glCullFace(GL_FRONT); | ||
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP); | glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP); | ||
− | + | RenderShadowVolumes; | |
glCullFace(GL_BACK); | glCullFace(GL_BACK); | ||
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP); | glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP); | ||
− | + | RenderShadowVolumes;</pre></code> | |
</td> | </td> | ||
</tr> | </tr> | ||
Zeile 59: | Zeile 60: | ||
=== zFail === | === zFail === | ||
− | Die von John Carmack | + | Die von John Carmack im Jahre 2000 "erfundene" Methode zählt die Schattenfragmente etwas anders : Für nach vorne zeigende Dreiecke wird der Wert im Stencilpuffer inkrementiert, wenn diese den Test '''nicht''' bestehen (daher der Name); und dekrementiert für nach hinten zeigende Dreiecke. Weiterhin muss man bei dieser Methode (damit die Fragmente korrekt gezählt werden) ein geschlossenes Schattenvolumen erstellen, das neben der extrudierten (meist in die Unendlichkeit) Silhouette des schattenwerfenden Objektes sowohl einen vorderen Deckel (''Front-Cap'') als auch einen abschliessenden (''Back-Cap'') hat. |
Der große Vorteil (auf den man in den seltensten Fällen verzichten) kann ist hier die Tatsache das zFail auch dann korrekte Schatten darstellt wenn der Betrachter in das Volumen eindringt. Nachteilig ist aber das man bedingt durch Deckel und Boden für die Schattenvolumen mehr Berechnungen und Pixeltests durchführen muss. Im Normalfall findet man deshalb eine Kombination aus beiden Techniken in einer Anwendung (zPass generell, wenn Betrachter in einem Volumen ist, dann zFail). | Der große Vorteil (auf den man in den seltensten Fällen verzichten) kann ist hier die Tatsache das zFail auch dann korrekte Schatten darstellt wenn der Betrachter in das Volumen eindringt. Nachteilig ist aber das man bedingt durch Deckel und Boden für die Schattenvolumen mehr Berechnungen und Pixeltests durchführen muss. Im Normalfall findet man deshalb eine Kombination aus beiden Techniken in einer Anwendung (zPass generell, wenn Betrachter in einem Volumen ist, dann zFail). | ||
Zeile 67: | Zeile 68: | ||
glCullFace(GL_FRONT); | glCullFace(GL_FRONT); | ||
glStencilOp(GL_KEEP, GL_INCR_WRAP, GL_KEEP); | glStencilOp(GL_KEEP, GL_INCR_WRAP, GL_KEEP); | ||
− | + | RenderShadowVolumes; | |
glCullFace(GL_BACK); | glCullFace(GL_BACK); | ||
glStencilOp(GL_KEEP, GL_DECR_WRAP, GL_KEEP); | glStencilOp(GL_KEEP, GL_DECR_WRAP, GL_KEEP); | ||
− | + | RenderShadowVolumes;</pre></code> | |
</td> | </td> | ||
</tr> | </tr> | ||
Zeile 84: | Zeile 85: | ||
'''Negativ :''' | '''Negativ :''' | ||
* Benötigt Kenntnis über die zugrundeliegende Geometrie (für die Schattensilhouette) | * Benötigt Kenntnis über die zugrundeliegende Geometrie (für die Schattensilhouette) | ||
− | * Silhouette muss auf der CPU errechnet werden (->CPU-Lastig) | + | * [[Silhouette]] muss auf der CPU errechnet werden (->CPU-Lastig) |
* Verbraucht sehr viel Füllrate | * Verbraucht sehr viel Füllrate | ||
== Beispiel == | == Beispiel == | ||
− | [[Bild: | + | [[Bild:Shadowvolume_scene.jpg]]<br> |
− | Zu sehen ist hier eine Szene die mittels volumetrischer Stencilschatten schattiert wurde. Die roten Umrandungen stellen die Silhouette der Szene ggü. der Lichtquelle dar, während die blauen Linien die Schattenvolumen darstellen ( | + | Zu sehen ist hier eine Szene die mittels volumetrischer Stencilschatten schattiert wurde. Die roten Umrandungen stellen die Silhouette der Szene ggü. der Lichtquelle dar, während die blauen Linien die Schattenvolumen darstellen (extrudiert in die Unendlichkeit). |
+ | |||
+ | == Zweiseitiger Stenciltest == | ||
+ | Die Performance kann mithilfe eines zweiseitigen Stenciltests verbessert werden, welcher vor OpenGL 2.0 mit der Extension [[GL_EXT_stencil_two_side]] bzw. [[GL_ATI_separate_stencil]] zur Verfügung stand. | ||
+ | Ab OpenGL 2.0 wurde [[GL_ATI_separate_stencil]] in den Kern übernommen und man kann von nun an mit [[glStencilOpSeparate]] für Front- und Backface-Polygone gleichzeitig verschiedene Operationen angeben. | ||
+ | Somit lässt sich der Algorithmus in einem einzelnen Pass realisieren. | ||
+ | |||
+ | === Beispiel [[glActiveStencilFaceEXT]] === | ||
+ | Hier ein Beispiel, wie man Stencilschatten in einem Pass mithilfe der Extensions [[GL_EXT_stencil_two_side]] und [[GL_EXT_stencil_wrap]] umsetzt (zPass) : | ||
+ | <source lang="cpp"> | ||
+ | glDepthMask(0); | ||
+ | glColorMask(0,0,0,0); | ||
+ | glDisable(GL_CULL_FACE); | ||
+ | glEnable(GL_STENCIL_TEST); | ||
+ | glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT); | ||
+ | |||
+ | glActiveStencilFaceEXT(GL_BACK); | ||
+ | glStencilOp(GL_KEEP, // stencil test fail | ||
+ | GL_KEEP, // depth test fail | ||
+ | GL_DECR_WRAP_EXT); // depth test pass | ||
+ | glStencilMask(~0); | ||
+ | glStencilFunc(GL_ALWAYS, 0, ~0); | ||
+ | |||
+ | glActiveStencilFaceEXT(GL_FRONT); | ||
+ | glStencilOp(GL_KEEP, // stencil test fail | ||
+ | GL_KEEP, // depth test fail | ||
+ | GL_INCR_WRAP_EXT); // depth test pass | ||
+ | glStencilMask(~0); | ||
+ | glStencilFunc(GL_ALWAYS, 0, ~0); | ||
+ | |||
+ | renderShadowVolumePolygons(); | ||
+ | </source> | ||
== Ressourcen == | == Ressourcen == | ||
Zeile 97: | Zeile 129: | ||
*[http://developer.nvidia.com/object/fast_shadow_volumes.html Fast, Practical, and Robust Shadow Volumes (NVidia)] | *[http://developer.nvidia.com/object/fast_shadow_volumes.html Fast, Practical, and Robust Shadow Volumes (NVidia)] | ||
*[http://developer.nvidia.com/object/robust_shadow_volumes.html Practical and Robust Shadow Volumes (NVidia)] | *[http://developer.nvidia.com/object/robust_shadow_volumes.html Practical and Robust Shadow Volumes (NVidia)] | ||
+ | |||
+ | [[Kategorie:Technik_oder_Algorithmus]] |
Aktuelle Version vom 10. November 2009, 18:30 Uhr
(weitere exzellente Artikel) |
Inhaltsverzeichnis
Konzept
Bei dieser Technik nutzt man den (seit ~2000 von fast allen Grafikkarten angebotenen) Stencilpuffer um dort die im Schatten liegenden Bereiche der Szene abzulegen. Später werden dann mit einem passenden Stencilvergleich die Schatten dargestellt.
Dazu wird für jedes Objekt ausgehend von seiner Silhouette (es entsteht immer dort eine Silhouetten-Kante, wo ein dem Licht abgewandtes und ein dem Licht zugewandtes Dreieck sich treffen) durch extrudieren ihrer Eckpunkte (im Idealfall in die Unendlichkeit, am einfachsten lösbar über die W-Koordinate) ein Volumen erstellt das den Bereich des Objektes darstellt den es schattiert.
Geschichte
1977 - Erfunden von Crow : Software-Renderer
1984 - Brotman und Badler : Software-Tiefenpuffer und viele Punktlichter für weiche Schatten
1985 - Fuchs und Co. : Erste Hardwareimplementation und Volumentechnik statt Raytracing
1986 - Bergeron : Behandlung offener Modelle, Nicht-Planare Polygone
1988 - Forunier & Fussell : Theorie zum Zählen der Schattenvolumen in einem Puffer
1991 - Heidmann : Implementation in IRIS GL über Stencilpuffer
1992 - Akeley & Foren : Der für IRIS GL entwickelte Stencilpuffer wird patentiert und in OpenGL 1.0 implementiert
1996 - Deifenbach : Multi-Pass Shattenvolumen
1999 - Dietrich : ZFail-Methode vorgestellt
1999 - Kilgard : Invertierter Algorithmus für planare Ausschnitte
2000 - Carmack : Erste detaillierte Diskussion zur Gleichheit von ZPass und ZFail
2001 - Kilgard : ZPass mit Capping vorgestellt
2002 - Everitt & Kilgard : Mehrere Techniken für eine robuste Lösung
(Teilweise entnommen aus dem Dokument "Optimized Stencil Shadow Volumes" von Cass Everitt & Mark J. Kilgard)
Zukunft
Zumindest für die in der Spieleindustrie treibenden "Kraft" in Sachen OpenGL, John Carmack (id Software), gehört die Zukunft klar den Schatten Volumen. Zumal die zwei frappierendsten aktuellen Nachteile (Ermitteln der Silhouette und Extrudieren eben dieser für das Volumen, sowie die hohe Anforderung an die Füllrate) dank schneller werdender Grafikkarten und CPUs immer weiter in den Hintergrund rücken. So kann man inzwischen dank Vertexprogrammen alle Eckpunkte der Silhouette einfach auf der GPU extrudieren. Auch die Tatsache, dass diese Technik nur sehr scharfkantige Schatten wirft, lässt sich via Jittering (mehrfachem, versetzem Rendern der Schattenvolumen mit unterschiedlicher Helligkeit) spätestens dann realisieren, wenn Grafikkarten genug Füllrate anbieten, und eben genau diese steigt von Generation zu Generation recht stetig an.
Grundlegende Funktionsweise
Um eine Szene mit volumetrischen Stencilschatten zu rendern sieht der Renderablauf im Normalfall wie folgt aus :
- Szene nur mit ambientem Lichtanteil in den Farbpuffer rendern
- Silhouette zwischen Objekten und Lichtquellen errechnen
- Silhouetten extrudieren (und je nach Technik noch Deckel für das Volumen erstellen)
- Stenciltest aktivieren und erstellte Schattenvolumen dort hinein rendern (mit unterschiedlichen Stenciloperationen für Vorder- und Rückseite)
- Szene mit diffusem Lichtanteil rendern (da Schatten im Stencilpuffer liegen wird die Szene jetzt schattiert)
Methoden
zPass
Bei dieser (zuerst entwickelten) Methode inkrementieren nach vorne zeigende Dreiecke den Wert im Stencilpuffer, wenn diese den Test passieren; und nach hinten zeigende Dreiecke dekrementieren diesen Wert. Nachteil dieser Methode ist jedoch die Tatsache das es zu Fehlern beim Zählen der Schattenwerte im Stencilpuffer kommt, sobald der Betrachter in ein Schattenvolumen eintritt. Um dies zu lösen gibt es jedoch die zFail-Methode.
|
zFail
Die von John Carmack im Jahre 2000 "erfundene" Methode zählt die Schattenfragmente etwas anders : Für nach vorne zeigende Dreiecke wird der Wert im Stencilpuffer inkrementiert, wenn diese den Test nicht bestehen (daher der Name); und dekrementiert für nach hinten zeigende Dreiecke. Weiterhin muss man bei dieser Methode (damit die Fragmente korrekt gezählt werden) ein geschlossenes Schattenvolumen erstellen, das neben der extrudierten (meist in die Unendlichkeit) Silhouette des schattenwerfenden Objektes sowohl einen vorderen Deckel (Front-Cap) als auch einen abschliessenden (Back-Cap) hat. Der große Vorteil (auf den man in den seltensten Fällen verzichten) kann ist hier die Tatsache das zFail auch dann korrekte Schatten darstellt wenn der Betrachter in das Volumen eindringt. Nachteilig ist aber das man bedingt durch Deckel und Boden für die Schattenvolumen mehr Berechnungen und Pixeltests durchführen muss. Im Normalfall findet man deshalb eine Kombination aus beiden Techniken in einer Anwendung (zPass generell, wenn Betrachter in einem Volumen ist, dann zFail).
|
Vor- und Nachteile
Positiv :
- Sehr hohe Details (kein Aliasing)
- Selbstschattierung für schattenwerfende Objekte
Negativ :
- Benötigt Kenntnis über die zugrundeliegende Geometrie (für die Schattensilhouette)
- Silhouette muss auf der CPU errechnet werden (->CPU-Lastig)
- Verbraucht sehr viel Füllrate
Beispiel
Zu sehen ist hier eine Szene die mittels volumetrischer Stencilschatten schattiert wurde. Die roten Umrandungen stellen die Silhouette der Szene ggü. der Lichtquelle dar, während die blauen Linien die Schattenvolumen darstellen (extrudiert in die Unendlichkeit).
Zweiseitiger Stenciltest
Die Performance kann mithilfe eines zweiseitigen Stenciltests verbessert werden, welcher vor OpenGL 2.0 mit der Extension GL_EXT_stencil_two_side bzw. GL_ATI_separate_stencil zur Verfügung stand. Ab OpenGL 2.0 wurde GL_ATI_separate_stencil in den Kern übernommen und man kann von nun an mit glStencilOpSeparate für Front- und Backface-Polygone gleichzeitig verschiedene Operationen angeben. Somit lässt sich der Algorithmus in einem einzelnen Pass realisieren.
Beispiel glActiveStencilFaceEXT
Hier ein Beispiel, wie man Stencilschatten in einem Pass mithilfe der Extensions GL_EXT_stencil_two_side und GL_EXT_stencil_wrap umsetzt (zPass) :
glDepthMask(0);
glColorMask(0,0,0,0);
glDisable(GL_CULL_FACE);
glEnable(GL_STENCIL_TEST);
glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
glActiveStencilFaceEXT(GL_BACK);
glStencilOp(GL_KEEP, // stencil test fail
GL_KEEP, // depth test fail
GL_DECR_WRAP_EXT); // depth test pass
glStencilMask(~0);
glStencilFunc(GL_ALWAYS, 0, ~0);
glActiveStencilFaceEXT(GL_FRONT);
glStencilOp(GL_KEEP, // stencil test fail
GL_KEEP, // depth test fail
GL_INCR_WRAP_EXT); // depth test pass
glStencilMask(~0);
glStencilFunc(GL_ALWAYS, 0, ~0);
renderShadowVolumePolygons();