Signatur
Beschreibung
Mit framebufferRenderbuffer() verbindest du ein Renderbuffer-Objekt mit einem Anhangspunkt (attachment point) des Framebuffers, der gerade an target gebunden ist. Renderbuffer sind Speicherbereiche, die für das Offscreen-Rendering optimiert sind. Anders als Texturen kann man sie im Shader aber nicht als Sampler auslesen.
Typischerweise nutzt man diese Methode für den Tiefen- und Stencil-Puffer eines Framebuffers, der in eine Textur rendert. Die Farbe landet dann in einer Textur (über framebufferTexture2D()), die Tiefeninformation in einem Renderbuffer. In WebGL 2 kommen dazu Multisample-Renderbuffer (renderbufferStorageMultisample()), die man anschließend mit blitFramebuffer() auflöst.
Zuerst musst du den Framebuffer mit bindFramebuffer() binden und den Speicher des Renderbuffers mit renderbufferStorage() anlegen. Das interne Format muss zum Anhangspunkt passen, zum Beispiel DEPTH_COMPONENT16 für DEPTH_ATTACHMENT. Danach solltest du mit checkFramebufferStatus() prüfen, ob der Framebuffer vollständig ist.
Übergibst du für renderbuffer den Wert null, löst du den aktuellen Anhang an diesem Anhangspunkt.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $target Pflicht | GLenum | Ziel, an das der Framebuffer gebunden ist. WebGL 1: nur gl.FRAMEBUFFER. WebGL 2 zusätzlich gl.DRAW_FRAMEBUFFER und gl.READ_FRAMEBUFFER. |
|
| $attachment Pflicht | GLenum | Anhangspunkt: gl.COLOR_ATTACHMENT0, gl.DEPTH_ATTACHMENT, gl.STENCIL_ATTACHMENT oder gl.DEPTH_STENCIL_ATTACHMENT. In WebGL 2 zusätzlich COLOR_ATTACHMENT1 bis COLOR_ATTACHMENT15. In WebGL 1 gibt es weitere Farb-Anhänge nur mit der Erweiterung WEBGL_draw_buffers. |
|
| $renderbuffertarget Pflicht | GLenum | Muss gl.RENDERBUFFER sein. |
|
| $renderbuffer Pflicht | WebGLRenderbuffer | null | Das Renderbuffer-Objekt, das angehängt wird. Mit null löst du den bestehenden Anhang. |
Rückgabewert
undefined). Fehler meldet die Methode über gl.getError(), zum Beispiel INVALID_ENUM oder INVALID_OPERATION.Beispiele
Tiefenpuffer für Render-to-Texture anhängen
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const width = 512, height = 512;
// Farbziel: Textur
const colorTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, colorTex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
// Tiefenziel: Renderbuffer
const depthRb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthRb);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthRb);
const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
console.log(status === gl.FRAMEBUFFER_COMPLETE ? 'Framebuffer vollständig' : `Fehler: 0x${status.toString(16)}`);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
Kombinierter Tiefen-/Stencil-Puffer (WebGL 1)
const gl = document.querySelector('canvas').getContext('webgl');
const dsRb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, dsRb);
// In WebGL 1 ist DEPTH_STENCIL das passende Format
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, 256, 256);
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
const colorRb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, colorRb);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, 256, 256);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorRb);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, dsRb);
console.log(gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE);
Multisampling-Kantenglättung mit WebGL 2 und blitFramebuffer
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2', { antialias: false });
const { width, height } = canvas;
const samples = Math.min(4, gl.getParameter(gl.MAX_SAMPLES));
const msColor = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, msColor);
gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.RGBA8, width, height);
const msDepth = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, msDepth);
gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.DEPTH_COMPONENT24, width, height);
const msFbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, msFbo);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, msColor);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, msDepth);
// ... Szene in msFbo zeichnen ...
gl.clearColor(0.1, 0.2, 0.3, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Auf den Canvas auflösen
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, msFbo);
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
gl.blitFramebuffer(0, 0, width, height, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST);