Start · Sprachen · JavaScript · Referenz · OES_fbo_render_mipmap extension

OES_fbo_render_mipmap extension

Schnittstelle

WebGL-1-Erweiterung, mit der beliebige Mipmap-Ebenen einer Textur (nicht nur Ebene 0) per <code>framebufferTexture2D()</code> an ein Framebuffer-Objekt angehängt werden können.

seit JavaScript WebGL 1 (Erweiterung); in WebGL 2 standardmäßig en Kategorie: webapi

Signatur

interface OES_fbo_render_mipmap

Beschreibung

OES_fbo_render_mipmap ist eine Erweiterung der WebGL API. In reinem WebGL 1 muss der Parameter level von WebGLRenderingContext.framebufferTexture2D() immer 0 sein, sonst wird der Fehler INVALID_VALUE ausgelöst. Ist die Erweiterung aktiviert, darf level jede gültige Mipmap-Ebene der Textur angeben. So lässt sich direkt in kleinere Mipmap-Stufen rendern.

Die Erweiterung stellt keine eigenen Methoden oder Konstanten bereit. Das zurückgegebene Objekt dient nur als Nachweis, dass die Erweiterung aktiv ist. Sie wird über gl.getExtension("OES_fbo_render_mipmap") aktiviert. Erst danach gilt das erweiterte Verhalten von framebufferTexture2D().

Typische Anwendungsfälle:

  • eigene Mipmap-Erzeugung mit Filtern, die besser sind als bei generateMipmap() (z. B. Gauß- oder Kaiser-Filter),
  • Bloom- und Weichzeichner-Ketten, bei denen jede Stufe in eine kleinere Mip-Ebene geschrieben wird,
  • vorgefilterte Umgebungs-Maps für PBR, bei denen jede Rauheitsstufe einer Mip-Ebene entspricht,
  • Hierarchical-Z- bzw. Tiefenpyramiden für Occlusion Culling.

In WebGL 2 ist diese Funktion fester Bestandteil der API. Dort steht die Erweiterung nicht zur Verfügung, weil sie nicht nötig ist.

Parameter

Name Typ Default Beschreibung
$name Pflicht string Wird an gl.getExtension() übergeben und muss genau "OES_fbo_render_mipmap" lauten.

Rückgabewert

Typ
OES_fbo_render_mipmap | null
Beschreibung
getExtension() gibt ein Erweiterungsobjekt ohne eigene Methoden zurück, wenn die Erweiterung unterstützt wird. Andernfalls 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('OES_fbo_render_mipmap');
if (ext) {
  console.log('Rendern in Mipmap-Ebenen möglich');
} else {
  console.log('Nicht unterstützt – nur Ebene 0 als Render-Ziel');
}
Rendern in Mipmap-Ebenen möglich

In Mip-Ebene 1 einer Textur rendern (WebGL 1)

const gl = document.createElement('canvas').getContext('webgl');
if (!gl.getExtension('OES_fbo_render_mipmap')) {
  throw new Error('OES_fbo_render_mipmap fehlt');
}

const size = 256; // Zweierpotenz ist für Mipmaps in WebGL 1 Pflicht
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);

// Speicher für alle Mip-Ebenen anlegen
for (let level = 0, s = size; s >= 1; level++, s >>= 1) {
  gl.texImage2D(gl.TEXTURE_2D, level, gl.RGBA, s, s, 0,
                gl.RGBA, gl.UNSIGNED_BYTE, null);
}
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);

const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
// level = 1 ist erst durch die Erweiterung erlaubt
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
                        gl.TEXTURE_2D, tex, 1);

const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
console.log(status === gl.FRAMEBUFFER_COMPLETE);

gl.viewport(0, 0, size >> 1, size >> 1); // Größe von Ebene 1: 128×128
gl.clearColor(1, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
true

Hilfsfunktion für WebGL 1 und WebGL 2

const canRenderToMipLevels = (gl) => {
  if (typeof WebGL2RenderingContext !== 'undefined' &&
      gl instanceof WebGL2RenderingContext) {
    return true; // in WebGL 2 fest eingebaut
  }
  return gl.getExtension('OES_fbo_render_mipmap') !== null;
};

const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2') ?? canvas.getContext('webgl');
console.log('Mip-Rendering:', canRenderToMipLevels(gl));
Mip-Rendering: true

Fehlerverhalten ohne Erweiterung

const gl = document.createElement('canvas').getContext('webgl');
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 64, 64, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texImage2D(gl.TEXTURE_2D, 1, gl.RGBA, 32, 32, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

gl.bindFramebuffer(gl.FRAMEBUFFER, gl.createFramebuffer());
// Erweiterung NICHT aktiviert
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 1);
console.log(gl.getError() === gl.INVALID_VALUE);
true

// Wichtig · Fallstricke

  • Erst aktivieren, dann nutzen: Die Erweiterung zu unterstützen reicht nicht. Sie muss vorher mit getExtension() aktiviert worden sein, sonst führt level > 0 zu INVALID_VALUE.
  • Nur WebGL 1: In einem WebGL2RenderingContext gibt getExtension("OES_fbo_render_mipmap") null zurück, obwohl das Verhalten dort standardmäßig verfügbar ist.
  • Feedback-Schleifen: In WebGL 1 gibt es kein TEXTURE_BASE_LEVEL und kein TEXTURE_MAX_LEVEL. Wenn eine Textur im Shader gelesen wird, während man in eine ihrer Mip-Ebenen rendert, meldet WebGL eine Feedback-Schleife. Die Folge ist INVALID_OPERATION beim Zeichnen. In der Praxis liest man deshalb aus einer zweiten Textur und wechselt zwischen beiden ab („Ping-Pong“). Alternativ nutzt man WebGL 2 mit eingeschränktem Ebenen-Bereich.
  • Zweierpotenzen: Mipmaps setzen in WebGL 1 Texturen voraus, deren Seitenlängen Zweierpotenzen sind. Außerdem muss für die angehängte Ebene ein Bild mit passender Größe angelegt sein. Das prüft man mit checkFramebufferStatus().
  • Viewport anpassen: Der Viewport muss zur Größe der jeweiligen Mip-Ebene passen, also size >> level. Sonst wird nur ein Teil gerendert.
  • Kompatibilität: Die Unterstützung hängt von Browser und GPU-Treiber ab und ist nicht überall vorhanden. Deshalb immer auf null prüfen und einen Ausweg vorsehen, z. B. generateMipmap() oder separate Texturen je Stufe.