Signatur
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
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);
}
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');
}
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));
}
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
// Wichtig · Fallstricke
- Nur WebGL 1: In einem
webgl2-Kontext liefertgetExtension("EXT_frag_depth")den Wertnull. Nutze dort stattdessengl_FragDepthin GLSL ES 3.00. - Zwei Schritte nötig: Du musst die Erweiterung per
getExtension()anfordern und im Shader mit#extension GL_EXT_frag_depth : enableeinschalten. Diese Direktive muss vor jeglichem anderen Code stehen. Fehlt einer der beiden Schritte, schlägt das Kompilieren fehl. - Leistung: Sobald ein Shader in
gl_FragDepthEXTschreibt, 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_FragDepthEXTverwendet, muss er in jedem Ausführungspfad einen Wert zuweisen, außer beidiscard. 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.