Start · Sprachen · JavaScript · Referenz · EXT_frag_depth extension

EXT_frag_depth extension

Schnittstelle

WebGL-1-Erweiterung, mit der ein Fragment-Shader über <code>gl_FragDepthEXT</code> selbst den Tiefenwert des aktuellen Fragments festlegen kann.

seit JavaScript WebGL 1 (Erweiterung); in WebGL 2 Kernfunktion (gl Kategorie: webapi

Signatur

interface EXT_frag_depth

Beschreibung

Die Erweiterung EXT_frag_depth gehört zur WebGL-API und ist nur in einem WebGL-1-Kontext verfügbar. Sie stellt im Fragment-Shader die zusätzliche Ausgabevariable gl_FragDepthEXT bereit. Damit legt der Shader den Tiefenwert eines Fragments selbst fest, statt den automatisch interpolierten Wert aus gl_FragCoord.z zu übernehmen.

Das Interface hat keine eigenen Methoden, Eigenschaften oder Konstanten. Du aktivierst es mit gl.getExtension("EXT_frag_depth"). Im GLSL-Code schaltest du es zusätzlich mit #extension GL_EXT_frag_depth : enable ein. Erst danach kannst du in gl_FragDepthEXT einen Wert von 0.0 bis 1.0 schreiben.

Typische Einsatzfälle:

  • Impostors: Kugeln oder Zylinder werden als Billboard-Quad gezeichnet, verdecken sich aber trotzdem pixelgenau richtig.
  • Raymarching: Objekte aus Signed Distance Fields (SDF) werden mit echten Dreiecksmeshes gemischt.
  • Logarithmischer Tiefenpuffer: Z-Fighting bei sehr großen Sichtweiten wird verringert.
  • Volumen- und Partikeleffekte: Sie brauchen eigene Tiefenwerte.

In WebGL 2 ist diese Funktion fest eingebaut. Dort schreibt man in GLSL ES 3.00 (#version 300 es) direkt in gl_FragDepth. Die Erweiterung wird dort nicht mehr angeboten.

Rückgabewert

Typ
EXT_frag_depth | null
Beschreibung
gl.getExtension("EXT_frag_depth") liefert ein Erweiterungsobjekt ohne eigene Mitglieder. Wird die Erweiterung nicht unterstützt, ist der Rückgabewert null.

Beispiele

Erweiterung aktivieren und Unterstützung prüfen

const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');

const ext = gl.getExtension('EXT_frag_depth');
if (!ext) {
  console.warn('EXT_frag_depth wird nicht unterstützt');
} else {
  console.log('EXT_frag_depth aktiv:', ext instanceof EXT_frag_depth);
}
EXT_frag_depth aktiv: true

Fragment-Shader mit gl_FragDepthEXT kompilieren

const gl = document.createElement('canvas').getContext('webgl');
gl.getExtension('EXT_frag_depth');

const fsSource = `#extension GL_EXT_frag_depth : enable
precision mediump float;
varying vec2 vUv;

void main() {
  // Tiefe nimmt von links nach rechts zu
  gl_FragDepthEXT = vUv.x;
  gl_FragColor = vec4(vUv, 0.0, 1.0);
}`;

const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, fsSource);
gl.compileShader(shader);

if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
  console.error(gl.getShaderInfoLog(shader));
} else {
  console.log('Shader erfolgreich kompiliert');
}
Shader erfolgreich kompiliert

Kugel-Impostor mit korrekter Tiefe

// Ein Quad wird als Kugel dargestellt; die Tiefe wird pro Pixel berechnet
const fsSphere = `#extension GL_EXT_frag_depth : enable
precision highp float;
varying vec2 vCoord;      // -1..1 innerhalb des Quads
uniform float uCenterDepth; // Tiefe des Kugelmittelpunkts (0..1)
uniform float uRadiusDepth; // Radius im Tiefenbereich

void main() {
  float r2 = dot(vCoord, vCoord);
  if (r2 > 1.0) discard;      // außerhalb der Kugel
  float z = sqrt(1.0 - r2);   // Höhe der Kugeloberfläche
  gl_FragDepthEXT = uCenterDepth - z * uRadiusDepth;
  vec3 n = vec3(vCoord, z);
  float light = max(dot(n, normalize(vec3(0.4, 0.6, 1.0))), 0.0);
  gl_FragColor = vec4(vec3(0.2, 0.5, 1.0) * light, 1.0);
}`;

const gl = document.createElement('canvas').getContext('webgl');
if (gl.getExtension('EXT_frag_depth')) {
  const sh = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(sh, fsSphere);
  gl.compileShader(sh);
  console.log(gl.getShaderParameter(sh, gl.COMPILE_STATUS));
}
true

WebGL-2-Variante ohne Erweiterung

const gl2 = document.createElement('canvas').getContext('webgl2');

const fs = `#version 300 es
precision mediump float;
in vec2 vUv;
out vec4 outColor;

void main() {
  gl_FragDepth = vUv.y; // eingebaut in WebGL 2
  outColor = vec4(1.0);
}`;

const sh = gl2.createShader(gl2.FRAGMENT_SHADER);
gl2.shaderSource(sh, fs);
gl2.compileShader(sh);
console.log(gl2.getExtension('EXT_frag_depth')); // in WebGL 2 nicht verfügbar
null

// Wichtig · Fallstricke

  • Nur WebGL 1: In einem webgl2-Kontext liefert getExtension("EXT_frag_depth") den Wert null. Nutze dort stattdessen gl_FragDepth in GLSL ES 3.00.
  • Zwei Schritte nötig: Du musst die Erweiterung per getExtension() anfordern und im Shader mit #extension GL_EXT_frag_depth : enable einschalten. Diese Direktive muss vor jeglichem anderen Code stehen. Fehlt einer der beiden Schritte, schlägt das Kompilieren fehl.
  • Leistung: Sobald ein Shader in gl_FragDepthEXT schreibt, kann die GPU den frühen Tiefentest (Early-Z) nicht mehr nutzen. Verdeckte Fragmente werden dann trotzdem vollständig berechnet. Setze die Erweiterung daher nur bei den Objekten ein, die sie wirklich brauchen.
  • Immer schreiben: Wenn ein Shader gl_FragDepthEXT verwendet, muss er in jedem Ausführungspfad einen Wert zuweisen, außer bei discard. Sonst ist der Tiefenwert undefiniert.
  • Werte werden auf den mit gl.depthRange() gesetzten Bereich (Standard: 0 bis 1) begrenzt.
  • Kompatibilität: Wird von allen modernen Desktop-Browsern breit unterstützt. Auf älteren Mobilgeräten kann die Erweiterung fehlen. Prüfe daher immer den Rückgabewert und sieh eine Ersatzlösung vor.