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

WebGLRenderingContext.bindFramebuffer()

Methode

Bindet ein <code>WebGLFramebuffer</code> an ein Ziel, sodass Zeichen- und Lesebefehle in diesen Framebuffer statt auf das Canvas gehen.

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

Signatur

WebGLRenderingContext.prototype.bindFramebuffer(target, framebuffer)

Beschreibung

bindFramebuffer() legt fest, welcher Framebuffer als aktuelles Ziel für Zeichen- und Lesebefehle dient. Standardmäßig rendert WebGL in den Standard-Framebuffer, also in das <canvas>. Bindest du ein eigenes WebGLFramebuffer-Objekt, gehen alle folgenden Aufrufe wie drawArrays(), drawElements(), clear() und readPixels() an dessen Anhänge (Texturen oder Renderbuffer).

Gebraucht wird das vor allem für Render-to-Texture: Nachbearbeitungseffekte wie Weichzeichnen oder Bloom, Schattenkarten, Picking (Objektauswahl über Farb-IDs), Spiegelungen oder GPGPU-Berechnungen. Übergibst du null, bindet WebGL wieder den Standard-Framebuffer, und es wird erneut auf das Canvas gezeichnet.

In WebGL 1 gibt es nur das Ziel gl.FRAMEBUFFER. In WebGL 2 (WebGL2RenderingContext) kommen gl.DRAW_FRAMEBUFFER und gl.READ_FRAMEBUFFER hinzu. Damit lassen sich Lese- und Schreibziel getrennt binden, etwa für blitFramebuffer(). gl.FRAMEBUFFER bindet dort beide Ziele gleichzeitig.

Parameter

Name Typ Default Beschreibung
$target Pflicht GLenum Das Bindungsziel. In WebGL 1 nur gl.FRAMEBUFFER. In WebGL 2 zusätzlich gl.DRAW_FRAMEBUFFER (Ziel für Zeichnen und Löschen) und gl.READ_FRAMEBUFFER (Quelle für readPixels, copyTexImage2D und blitFramebuffer).
$framebuffer Pflicht WebGLFramebuffer | null Das zu bindende Framebuffer-Objekt, erzeugt mit gl.createFramebuffer(). Mit null wird wieder der Standard-Framebuffer (das Canvas) gebunden.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Fehler meldet WebGL über gl.getError().

Beispiele

Framebuffer mit Textur-Anhang anlegen (Render-to-Texture)

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

// Zieltextur anlegen
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 512, 512, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

// Framebuffer anlegen und binden
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);

const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
console.log(status === gl.FRAMEBUFFER_COMPLETE ? 'Framebuffer bereit' : `Fehler: ${status}`);

// Wieder auf das Canvas umschalten
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
Framebuffer bereit

Zeichenschleife: erst in die Textur, dann auf das Canvas

const renderFrame = (gl, fbo, drawScene, drawPostProcess) => {
  // Durchlauf 1: Szene in den Offscreen-Framebuffer zeichnen
  gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  gl.viewport(0, 0, 512, 512);
  gl.clearColor(0, 0, 0, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
  drawScene();

  // Durchlauf 2: Ergebnis als Textur auf das Canvas bringen
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
  drawPostProcess();
};

Picking: ein Pixel aus dem Framebuffer auslesen

const pickAt = (gl, fbo, x, y) => {
  gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  const pixel = new Uint8Array(4);
  // WebGL-Koordinaten beginnen unten links
  gl.readPixels(x, 512 - y - 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  // Objekt-ID aus dem Rot- und Grünkanal zusammensetzen
  return pixel[0] + (pixel[1] << 8);
};

console.log(pickAt(gl, fbo, 100, 200));
z. B. 3

WebGL 2: Multisample-Framebuffer per Blit auflösen

const gl2 = document.querySelector('canvas').getContext('webgl2');
// msaaFbo und resolveFbo seien vorher angelegt
gl2.bindFramebuffer(gl2.READ_FRAMEBUFFER, msaaFbo);
gl2.bindFramebuffer(gl2.DRAW_FRAMEBUFFER, resolveFbo);
gl2.blitFramebuffer(0, 0, 512, 512, 0, 0, 512, 512, gl2.COLOR_BUFFER_BIT, gl2.NEAREST);
gl2.bindFramebuffer(gl2.FRAMEBUFFER, null);

// Wichtig · Fallstricke

  • Viewport wird nicht automatisch angepasst: Nach dem Umschalten musst du gl.viewport() selbst auf die Größe des Framebuffers bzw. des Canvas setzen. Sonst erscheint das Bild abgeschnitten oder verzerrt.
  • Vollständigkeit prüfen: Vor dem Zeichnen sollte gl.checkFramebufferStatus() den Wert FRAMEBUFFER_COMPLETE liefern. Andernfalls schlagen Zeichenbefehle mit INVALID_FRAMEBUFFER_OPERATION fehl.
  • Feedback-Schleife: Eine Textur darf nicht gleichzeitig am gebundenen Framebuffer hängen und im Shader gelesen werden. Das ist undefiniertes Verhalten bzw. ein INVALID_OPERATION-Fehler.
  • Ein ungültiges target erzeugt INVALID_ENUM. Ein bereits mit deleteFramebuffer() gelöschtes Objekt erzeugt INVALID_OPERATION. DRAW_FRAMEBUFFER und READ_FRAMEBUFFER gibt es nur in WebGL 2.
  • Häufiges Umschalten des Framebuffers ist auf mobilen GPUs (Tile-basiertes Rendern) teuer. Fasse Zeichendurchläufe deshalb möglichst zusammen.
  • Die Methode steht in allen modernen Browsern zur Verfügung, auch in OffscreenCanvas-Kontexten innerhalb von Web Workern.