3 Kantenverlauf auf Polygonen, Polygonoffset
13.010 Was sind die Grundlagen, um den Polygon Offset nutzen zu können ?
Es ist schwierig, mit OpenGL zwei auf annähernd gleicher Position (coplanar) liegende
Polygone korrekt darzustellen, so dass diese sich nicht durchdringen (z.B.
die Markierungen auf der Fahrbahn). Dafür gibt es zwei Gründe:
-
Zwei sich schneidende/überlappende Primitive mit verschiedenen Eckpunkten
können durch Rundungsfehler leicht abweichende Z-Werte erhalten. Das heisst,
einige Pixel der eigentlich nicht sichtbaren Fläche liegen für die OpenGL
vor den anderen und werden deshalb angezeigt.
-
Für coplanare Linien und Polygone können trotz Deckungsgleicheit
deutlich verschiedene Z-Werte für gleiche Pixel berechnet werden. Das liegt
daran, dass während der Rasterisation für Polygone eine Flächengleichung,
für Linien dagegen eine einfache Geradengleichung zur Interpolation genutzt wird.
Auch das Festlegen des Tiefentests auf GL_LEQUAL oder GL_EQUAL hilft nicht.
Polygon Offset war bereits in der OpenGL Version 1.0 als Extension verfügbar
und ist fester Bestandteil der OpenGL seit Version 1.1. Es erlaubt der Anwendung,
einem ausgefüllten Primitive einen zusätzlichen Tiefenoffset zu geben, der dieses Primitive
vor einem anderen an gleicher Position zeichnet. Mit OpenGL 1.1 ist es sogar möglich,
den angegebenen Offset getrennt für Flächen, Linien und Punkten anzugeben und
zu aktivieren. Damit kann ein Programm zunächst ein Primitiv zeichnen und das
zweite an gleicher Stelle, nachdem der Polygon Offset aktiviert wurde.
Der Polygon Offset kann zwar den Z-Wert von Flächen beeinflussen, aber
nicht den von Primitiven wie GL_POINTS, GL_LINES, GL_LINE_STRIP, oder GL_LINE_LOOP.
Damit kann man den Polygon Offset nutzen, um ein auf gleicher Höhe wie z.B.
eine Linie liegendes Polygon etwas nach hinten zu schieben, nicht aber um die Linien oder
Punkte nach vorn zu holen.
Da Polygon Offset den Z-Wert beim Rasterisieren beeinflusst, kann der im Tiefenbuffer
verändert vorliegende Wert auch das angezeigte Bild der Szene nachteilig
verändern. Unter vielen Umständen ist es möglich, dass unerwünschte
Durchdringungserscheinungen die Folge sind oder ein Objekt im Vordergrund gezeichnet wird, obwohl
es da gar nicht hingehört. Besonders sich schneidende Polygone können betroffen sein.
Als Startwert für die Parameter factor und units kann man
zunächst jeweils 1.0 wählen und dann für die Szene eine individuelle Anpassung
ermitteln.
13.020 Was bedeuten die beiden Parameter in der Funktion glPolygonOffset() ?
Polygon Offset wird durch zwei Parameter gesteuert. Das sind factor und
units (Faktor und Einheit). factor legt die maximale Abweichung in Z
(abhängig von X und Y) fest und units den kleinsten unterscheidbaren
Z-Wert. Die Kombination dieser Ergebnisse bestimmt den endgültigen Wert für den
Polygon Offset. Dieser wird im Bildschirmkoordinatensystem als positiver Wert (bzw.
negativ bei entsprechendem Vorzeichen der Parameter) dem vorgegebenen Z-Wert eines Vertex hinzu addiert.
Der Offset o berechnet sich wie folgt:
o = const1 * factor + const2 * units
Der Parameter factor wird benötigt, um als ausgefüllte
Flächen gezeichneten Primitive, die nicht parallel zur vorderen/hinteren
Clipping Fläche und damit in einem Winkel zum Betrachter liegen, korrekt darzustellen.
In diesem Fall kann der unterschiedliche Z-Wert für zwei coplanar liegende
Primitive der maximalen Abweichung in X oder Y entsprechen. Die Unterschiede in Z
sind gross für Primitive, deren Kanten nahe am Betrachter verlaufen (also
schräg zum Betrachter liegen) und klein für
Primitive, deren Flächen dem Betrachter zugewandt sind. Der Parameter factor
bestimmt also die unterschiedliche Abweichung in Z für diese beiden Fälle.
Eine typische Parameterangabe kann z.B. sein, beide Werte auf jeweils 1.0 und
den Polygon Offset auf GL_FILL zu setzen. Damit werden die als Flächen gezeichneten
Polygone in positiver Z-Richtung (in den Bildschirm hinein) verschoben.
Dann kann man das Polygon zweimal zeichnen, einmal als Fläche (bzw. Körper)
und einmal als Drahtgittermodell. So werden die Kanten des Polygons durch die Linien
des Drahtgittermodells nachgezeichnet.
In einem Winkel zum Betrachter liegende Flächen werden jetzt deutlich vom Augpunkt
weg geschoben, während bei einem annähernd parallel zur vorderen Clipping Fläche
liegenden Polygon nur ein minimaler Z-Offset addiert wird.
13.030 Was ist der Unterschied zwischen der Polygon Offset Extension von
OpenGL 1.0 und der Offset-Funktion ab OpenGL 1.1 ?
Die Polygon Offset Extension von OpenGL 1.0 liess sich nur für Polygone im
GL_FILL Modus verwenden, Drahtgitter- oder Eckpunktoffset war damit nicht möglich.
Die Extension arbeitet statt mit dem factor Parameter mit bias,
der direkt zum normalisierten Z-Wert addiert wird. Im Regelfall stellt der Wert 0.001
eine brauchbare Wahl dar.
Das GLUT Beispiel zeichnet zwei Zylinder, einmal mit der 1.0 Extension,
dann mit den OpenGL 1.1 Befehlen.
13.040 Warum arbeitet der Polygon Offset nicht, wenn ich eine Linie
über Farbflächen der Primitive zeichne ?
Polygon Offset beeinflusst gemäss seinem Namen auch nur Polygone, also
Primitive der Form: GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN,
GL_QUADS, GL_QUAD_STRIP und GL_POLYGON. Ab OpenGL 1.1 sind alle Darstellungsformen
(GL_FILL, GL_LINE, or GL_POINT) möglich.
Primitive der Art GL_POINTS, GL_LINES, GL_LINE_STRIP oder GL_LINE_LOOP lassen sich also nicht
mit einem Offset zu versehen.
13.050 Was habe ich noch für Optionen, um Primitive auf gleicher Ebene
ohne Nutzung des Polygon Offset zu zeichnen ?
Man kann den Effekt des Polygon Offset erreichen, indem man mit der Funktion
glDepthRange() arbeitet. Das geht z.B. mit folgendem Code:
glDepthRange (0.1, 1.0);
/* jetzt im Hintergrund liegende Geometrie zeichnen */
glDepthRange (0.0, 0.9);
/* jetzt im Vordergrund liegende Geometrie zeichnen */
Dieser Code legt einen festen Offset in Z fest, ohne die Ausdehnung bzw. den
Winkel des Polygons zu berücksichtigen. Damit ist es ungefähr vergleichbar
mit einem factor = 0.0 des Polygon Offset.
Man kann auch coplanar liegende Primitive mit der Hilfe des Stencil Buffers zeichnen.
Das Red Book zeigt eine mögliche Lösung
auf. Als Beispiel kann auch folgender Code dienen:
-
Zunächst werden die Kanten in den Farb-, Z- und Stencil Buffer gezeichnet.
-
Dann wird das Polygon im GL_FILL Modus in den Farb- und Tiefenbuffer gezeichnet,
wobei die bereits im Stencil Buffer belegten Bereiche ausgelassen werden.
-
Nun wird der Kantenverlauf ausschliesslich in den Stencil Buffer gezeichnet, so dass
dieser wieder gelöscht wird.
Auf einigen SGI Systemen steht auch die SGIX_reference_plane Extension zur
Verfügung. Damit kann man eine gemeinsame Flächengleichung für coplanare
Primitive festlegen. Wird diese Flächengleichung aktiviert, werden auch alle
Z-Werte der verschiedenen Primitive hierüber berechnet und sind damit
garantiert identisch.
|