Signatur
Beschreibung
EXT_shader_texture_lod ist eine Erweiterung für WebGL 1. Normalerweise wählt die GPU im Fragment-Shader das Mipmap-Level einer Textur automatisch aus. Grundlage dafür sind die Bildschirm-Ableitungen der Texturkoordinaten. Mit dieser Erweiterung bestimmt der Shader das Level selbst, entweder direkt als LOD-Wert oder über eigene Gradienten.
Das Erweiterungsobjekt in JavaScript hat keine eigenen Methoden oder Konstanten. Es genügt, gl.getExtension('EXT_shader_texture_lod') aufzurufen. Danach aktiviert der GLSL-Code die Erweiterung mit #extension GL_EXT_shader_texture_lod : enable. Anschließend stehen im Fragment-Shader diese Funktionen bereit:
texture2DLodEXT(sampler2D, vec2 coord, float lod)texture2DProjLodEXT(sampler2D, vec3|vec4 coord, float lod)textureCubeLodEXT(samplerCube, vec3 coord, float lod)texture2DGradEXT(sampler2D, vec2 coord, vec2 dPdx, vec2 dPdy)texture2DProjGradEXT(sampler2D, vec3|vec4 coord, vec2 dPdx, vec2 dPdy)textureCubeGradEXT(samplerCube, vec3 coord, vec3 dPdx, vec3 dPdy)
Typische Einsatzfälle:
- Physikalisch basiertes Rendering (PBR): Eine vorgefilterte Umgebungs-Cubemap wird passend zur Rauheit der Oberfläche in einem bestimmten Mipmap-Level gelesen.
- Texturatlanten mit Kachelung:
fract()erzeugt Sprünge in den Koordinaten, und die automatisch berechneten Ableitungen werden dort riesig. Mit eigenen Gradienten entstehen keine sichtbaren Nähte. - Gezielte Unschärfe und Nachbearbeitung: Bloom-, Tiefenschärfe- oder Blur-Effekte lesen absichtlich gröbere Mipmap-Stufen.
- Texturzugriff in Verzweigungen und Schleifen: Dort sind die automatischen Ableitungen undefiniert. Ein ausdrücklicher LOD macht das Ergebnis vorhersagbar.
Rückgabewert
gl.getExtension('EXT_shader_texture_lod') gibt ein Erweiterungsobjekt ohne eigene Mitglieder zurück. 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_shader_texture_lod');
if (ext) {
console.log('EXT_shader_texture_lod verfügbar');
} else {
console.warn('Nicht unterstützt – Fallback auf texture2D mit Bias nötig');
}
PBR: Umgebungs-Cubemap passend zur Rauheit lesen
const gl = document.querySelector('canvas').getContext('webgl');
if (!gl.getExtension('EXT_shader_texture_lod')) {
throw new Error('EXT_shader_texture_lod fehlt');
}
const fragmentSource = `
#extension GL_EXT_shader_texture_lod : enable
precision mediump float;
uniform samplerCube uEnvMap;
uniform float uRoughness; // 0.0 = glatt, 1.0 = rau
uniform float uMaxLod; // z. B. log2(Kantenlänge)
varying vec3 vReflectDir;
void main() {
float lod = uRoughness * uMaxLod;
vec3 color = textureCubeLodEXT(uEnvMap, normalize(vReflectDir), lod).rgb;
gl_FragColor = vec4(color, 1.0);
}`;
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, fragmentSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(shader));
} else {
console.log('Shader kompiliert');
}
Nahtlose Kachelung im Texturatlas mit eigenen Gradienten
const gl = document.querySelector('canvas').getContext('webgl');
gl.getExtension('EXT_shader_texture_lod');
// dFdx/dFdy benötigen zusätzlich OES_standard_derivatives
gl.getExtension('OES_standard_derivatives');
const fragmentSource = `
#extension GL_EXT_shader_texture_lod : enable
#extension GL_OES_standard_derivatives : enable
precision mediump float;
uniform sampler2D uAtlas;
uniform vec4 uTileRect; // xy = Offset, zw = Größe im Atlas
varying vec2 vUv;
void main() {
vec2 tiled = fract(vUv * 4.0);
vec2 atlasUv = uTileRect.xy + tiled * uTileRect.zw;
// Gradienten aus den stetigen Koordinaten, nicht aus fract()
vec2 grad = vUv * 4.0 * uTileRect.zw;
gl_FragColor = texture2DGradEXT(uAtlas, atlasUv, dFdx(grad), dFdy(grad));
}`;
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, fragmentSource);
gl.compileShader(shader);
console.log(gl.getShaderParameter(shader, gl.COMPILE_STATUS));
// Wichtig · Fallstricke
- Reihenfolge:
gl.getExtension()muss vor dem Kompilieren des Shaders aufgerufen werden. Sonst bricht das Kompilieren bei der#extension-Direktive oder bei den*EXT-Funktionen ab. - Die
#extension-Direktive muss vor allen anderen Anweisungen stehen, also auch vorprecision. - WebGL 2: Dort gibt es diese Erweiterung nicht. In GLSL ES 3.00 (
#version 300 es) sindtextureLod()undtextureGrad()fest eingebaut. - Die Funktionen sind nur im Fragment-Shader verfügbar. Im Vertex-Shader von WebGL 1 gibt es bereits
texture2DLod()ohne Suffix. - Die Textur braucht vollständige Mipmaps (
gl.generateMipmap()) und einen Mipmap-Filter wiegl.LINEAR_MIPMAP_LINEAR. Sonst hat der LOD-Wert keine Wirkung. In WebGL 1 setztgenerateMipmapTexturen mit Zweierpotenz-Maßen voraus. - Für
dFdx/dFdyist zusätzlichOES_standard_derivativesnötig. - Kompatibilität: Auf Desktop-Browsern breit unterstützt, auf älteren Mobilgeräten teils nicht. Plane immer einen Fallback ein, etwa
texture2D(sampler, uv, bias).