Start · Sprachen · JavaScript · Referenz · WebGLRenderingContext.polygonOffset()

WebGLRenderingContext.polygonOffset()

Methode

Legt Skalierungsfaktor und Einheiten fest, mit denen WebGL beim Rastern von Polygonen einen Versatz auf die Tiefenwerte addiert, z. B. gegen Z-Fighting.

seit JavaScript WebGL 1.0 – Baseline: alle modernen Browser Kategorie: webapi

Signatur

WebGLRenderingContext.prototype.polygonOffset(factor, units)

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

Typ
void
Beschreibung
Kein 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));
2 3 false

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 von polygonOffset() speichert nur die Werte.
  • Der Versatz gilt nur für Dreiecke. Für gl.LINES und gl.POINTS wird 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 r hä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.