Volumetrische Stencilschatten: Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
()
K (Verbesserungen durch zweiseitigen Stenciltest)
 
(28 dazwischenliegende Versionen von 8 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
= Volumetrische Stencilschatten =
+
{{Excellent}}
 +
== 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.
 +
 
 +
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<br>
 +
1984 - Brotman und Badler : Software-Tiefenpuffer und viele Punktlichter für weiche Schatten<br>
 +
1985 - Fuchs und Co. : Erste Hardwareimplementation und Volumentechnik statt Raytracing<br>
 +
1986 - Bergeron : Behandlung offener Modelle, Nicht-Planare Polygone<br>
 +
1988 - Forunier & Fussell : Theorie zum Zählen der Schattenvolumen in einem Puffer<br>
 +
1991 - Heidmann : Implementation in IRIS GL über Stencilpuffer<br>
 +
1992 - Akeley & Foren : Der für IRIS GL entwickelte Stencilpuffer wird patentiert und in OpenGL 1.0 implementiert<br>
 +
1996 - Deifenbach : Multi-Pass Shattenvolumen<br>
 +
1999 - Dietrich : ZFail-Methode vorgestellt<br>
 +
1999 - Kilgard : Invertierter Algorithmus für planare Ausschnitte<br>
 +
2000 - Carmack : Erste detaillierte Diskussion zur Gleichheit von ZPass und ZFail<br>
 +
2001 - Kilgard : ZPass mit Capping vorgestellt<br>
 +
2002 - Everitt & Kilgard : Mehrere Techniken für eine robuste Lösung<br>
  
== Konzept ==
+
(Teilweise entnommen aus dem Dokument ''"Optimized Stencil
 +
Shadow Volumes"'' von Cass Everitt & Mark J. Kilgard)
  
Bei dieser Technik nutzt man den (seit ~2000 von fast allen Grafikkarten angebotenen) [[Stempelpuffer|Stencilpuffer]] um dort die im Schatten liegenden Bereiche der Szene abzulegen. Später werden dann mit einem passenden Stencilvergleich die Schatten dargestellt.
+
== Zukunft ==
  
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 extruhieren 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.
+
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 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 ==
  
 
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 :
1. Szene nur mit ambientem Lichtanteil in den Farbpuffer rendern
+
# Szene nur mit ambientem Lichtanteil in den Farbpuffer rendern
2. Silhouette zwischen Objekten und Lichtquellen errechnen
+
# [[Silhouette]] zwischen Objekten und Lichtquellen errechnen
3. Silhouetten extruhieren (und je nach Technik noch Deckel für das Volumen erstellen)
+
# Silhouetten extrudieren (und je nach Technik noch Deckel für das Volumen erstellen)
4. 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)
5. 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)
  
 
== Methoden ==
 
== Methoden ==
Zeile 20: Zeile 43:
 
=== zPass ===
 
=== 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.
 
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ählend der Schattenwerte im Stencilpuffer kommt, sobald der Betrachter in ein Schattenvolumen eintritt. Um dies zu lösen gibt es jedoch die zFail-Methode.
+
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.
 +
 
 +
<table border="0">
 +
<tr>
 +
<td><code><pre>
 +
glCullFace(GL_FRONT);
 +
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP);
 +
RenderShadowVolumes;
 +
 
 +
glCullFace(GL_BACK);
 +
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP);
 +
RenderShadowVolumes;</pre></code>
 +
</td>
 +
</tr>
 +
</table>
  
 
=== zFail ===
 
=== zFail ===
Die von John Carmack (ID-Software) 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 extruhierten (meist in die Unendlichkeit) Silhouette des schattenwerfenden Objektes sowohl einen vorderen Deckel (''Front-Cap'') als auch einen abschliessenden (''Back-Cap'') hat.
+
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).
 +
 +
<table border="0">
 +
<tr>
 +
<td><code><pre>
 +
glCullFace(GL_FRONT);
 +
glStencilOp(GL_KEEP, GL_INCR_WRAP, GL_KEEP);
 +
RenderShadowVolumes;
 +
 +
glCullFace(GL_BACK);
 +
glStencilOp(GL_KEEP, GL_DECR_WRAP, GL_KEEP);
 +
RenderShadowVolumes;</pre></code>
 +
</td>
 +
</tr>
 +
</table>
  
 
== Vor- und Nachteile ==
 
== Vor- und Nachteile ==
  
'''Positiv :'''
+
'''Positiv :'''
- Sehr hohe Details (kein [[Aliasing]])
+
* Sehr hohe Details (kein [[Aliasing]])
- Selbstschattierung für schattenwerfende Objekte
+
* Selbstschattierung für schattenwerfende Objekte
 
   
 
   
'''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:shadowvolume_scene.jpg]]<br>
+
[[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 (extruhiert in die Unendlichkeit).
+
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 ==
[http://www.gamasutra.com/features/20021011/lengyel_01.htm "The Mechanics of Robust Stencil Shadows -  Eric Lengyel"]
+
*[http://www.gamasutra.com/features/20021011/lengyel_01.htm "The Mechanics of Robust Stencil Shadows -  Eric Lengyel"]
[http://www.gamedev.net/reference/articles/article1873.asp "The Theory of Stencil Shadow Volumes - Hun Yen Kwoon"]
+
*[http://www.gamedev.net/reference/articles/article1873.asp "The Theory of Stencil Shadow Volumes - Hun Yen Kwoon"]
[http://developer.nvidia.com/attach/6832 "John Carmack zum Thema Shadow Volumes"]
+
*[http://developer.nvidia.com/attach/6832 "John Carmack zum Thema Shadow Volumes"]
 +
*[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)]
 +
 
 +
[[Kategorie:Technik_oder_Algorithmus]]

Aktuelle Version vom 10. November 2009, 18:30 Uhr

Hinweis: Dieser Artikel wurde von den Benutzern des Wikis zum exzellenten Artikel berufen!
(weitere exzellente Artikel)
Excelent.jpg

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 :

  1. Szene nur mit ambientem Lichtanteil in den Farbpuffer rendern
  2. Silhouette zwischen Objekten und Lichtquellen errechnen
  3. Silhouetten extrudieren (und je nach Technik noch Deckel für das Volumen erstellen)
  4. Stenciltest aktivieren und erstellte Schattenvolumen dort hinein rendern (mit unterschiedlichen Stenciloperationen für Vorder- und Rückseite)
  5. 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.

 glCullFace(GL_FRONT);
 glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP);
 RenderShadowVolumes;

 glCullFace(GL_BACK);
 glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP);
 RenderShadowVolumes;

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).

glCullFace(GL_FRONT);
glStencilOp(GL_KEEP, GL_INCR_WRAP, GL_KEEP);
RenderShadowVolumes;

glCullFace(GL_BACK);
glStencilOp(GL_KEEP, GL_DECR_WRAP, GL_KEEP);
RenderShadowVolumes;

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

Shadowvolume scene.jpg
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();

Ressourcen