Signatur
Beschreibung
Die Methode polygonOffset() legt fest, wie stark die Tiefenwerte (Z-Werte) gerasterter Polygone verschoben werden, bevor der Tiefentest läuft. Der Versatz wird pro Fragment so berechnet: offset = factor × DZ + r × units. Dabei ist DZ die maximale Tiefenänderung des Polygons relativ zu seiner Bildschirmfläche (also seine Steigung) und r der kleinste Wert, der im Tiefenpuffer garantiert einen erkennbaren Unterschied ergibt.
Wirksam wird der Versatz erst, wenn er mit gl.enable(gl.POLYGON_OFFSET_FILL) eingeschaltet ist. Er gilt nur für gefüllte Dreiecke, nicht für Linien (gl.LINES) oder Punkte (gl.POINTS). WebGL unterstützt nur POLYGON_OFFSET_FILL, die OpenGL-Varianten POLYGON_OFFSET_LINE und POLYGON_OFFSET_POINT gibt es hier nicht.
Typische Einsatzfälle sind:
- Z-Fighting vermeiden, wenn zwei Flächen in derselben Ebene liegen, etwa Decals, Straßenmarkierungen oder Einschusslöcher auf einer Wand.
- Drahtgitter über gefüllten Flächen: Die Füllung wird mit positivem Versatz nach hinten geschoben, damit die Linien sauber sichtbar bleiben.
- Shadow Mapping: Beim Rendern der Shadow Map verhindert ein Versatz „Shadow Acne“ (Selbstverschattungs-Artefakte).
Positive Werte schieben die Fragmente vom Betrachter weg, negative Werte zu ihm hin. Das gilt beim Standard-Tiefentest gl.LESS bzw. gl.LEQUAL. Die aktuellen Werte lassen sich mit gl.getParameter(gl.POLYGON_OFFSET_FACTOR) und gl.getParameter(gl.POLYGON_OFFSET_UNITS) auslesen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $factor Pflicht | number (GLfloat) | 0 | Skalierungsfaktor für den variablen Tiefenversatz. Er wird mit der Tiefensteigung DZ des Polygons multipliziert und wirkt deshalb stärker bei schräg zur Kamera liegenden Flächen. |
| $units Pflicht | number (GLfloat) | 0 | Multiplikator für den konstanten, von der Implementierung abhängigen kleinsten Tiefenschritt r. Er sorgt für einen festen Mindestversatz. |
Rückgabewert
undefined).Beispiele
Decal auf einer Wand ohne Z-Fighting zeichnen
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
gl.enable(gl.DEPTH_TEST);
// 1. Wand normal zeichnen
// drawWall();
// 2. Decal in derselben Ebene leicht zum Betrachter ziehen
gl.enable(gl.POLYGON_OFFSET_FILL);
gl.polygonOffset(-1.0, -1.0);
// drawDecal();
gl.disable(gl.POLYGON_OFFSET_FILL);
Drahtgitter über gefüllter Geometrie
const gl = document.querySelector('canvas').getContext('webgl');
gl.enable(gl.DEPTH_TEST);
// Füllung nach hinten schieben, damit die Linien sichtbar bleiben
gl.enable(gl.POLYGON_OFFSET_FILL);
gl.polygonOffset(1.0, 1.0);
// gl.drawElements(gl.TRIANGLES, triCount, gl.UNSIGNED_SHORT, 0);
gl.disable(gl.POLYGON_OFFSET_FILL);
// Linien ohne Versatz darüberzeichnen (Offset wirkt auf Linien ohnehin nicht)
// gl.drawElements(gl.LINES, lineCount, gl.UNSIGNED_SHORT, 0);
Aktuelle Werte auslesen
const gl = document.createElement('canvas').getContext('webgl');
gl.polygonOffset(2, 3);
console.log(gl.getParameter(gl.POLYGON_OFFSET_FACTOR));
console.log(gl.getParameter(gl.POLYGON_OFFSET_UNITS));
console.log(gl.isEnabled(gl.POLYGON_OFFSET_FILL));
Shadow-Map-Pass mit Versatz gegen Shadow Acne
const renderShadowMap = (gl, shadowFramebuffer, drawScene) => {
gl.bindFramebuffer(gl.FRAMEBUFFER, shadowFramebuffer);
gl.clear(gl.DEPTH_BUFFER_BIT);
gl.enable(gl.POLYGON_OFFSET_FILL);
gl.polygonOffset(2.0, 4.0); // Werte je nach Szene anpassen
drawScene();
gl.disable(gl.POLYGON_OFFSET_FILL);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
};
// Wichtig · Fallstricke
- Ohne
gl.enable(gl.POLYGON_OFFSET_FILL)passiert nichts. Der Aufruf vonpolygonOffset()speichert nur die Werte. - Der Versatz gilt nur für Dreiecke. Für
gl.LINESundgl.POINTSwird er ignoriert. - Der Zustand gilt global für den ganzen Kontext. Nach dem Zeichnen sollte man ihn mit
gl.disable(gl.POLYGON_OFFSET_FILL)wieder abschalten, sonst sind alle folgenden Zeichenaufrufe betroffen. - Der Wert
rhängt von der Implementierung und vom Tiefenpuffer ab (16 oder 24 Bit). Gleiche Werte können deshalb auf verschiedener Hardware unterschiedlich wirken. Zu große Werte führen zu „Peter Panning“: Objekte scheinen dann über ihren Schatten zu schweben. - Das Vorzeichen hängt von der Tiefenfunktion ab. Bei umgekehrtem Tiefenpuffer (
gl.GREATER) kehrt sich die Richtung um. - Werte, die keine Zahl sind, werden in Zahlen umgewandelt. Ungültige Werte erzeugen keinen WebGL-Fehler.
- Kompatibilität: Die Methode gibt es in WebGL 1 und WebGL 2 (
WebGL2RenderingContext) in allen modernen Browsern.