Signatur
Beschreibung
renderbufferStorage() reserviert GPU-Speicher für das Renderbuffer-Objekt, das gerade mit gl.bindRenderbuffer(gl.RENDERBUFFER, rb) gebunden ist. Renderbuffer sind Bildpuffer, die man nicht als Textur ausliest. Sie eignen sich deshalb vor allem für Tiefen- und Stencil-Anhänge eines Framebuffers, also für Daten, die man beim Offscreen-Rendern braucht, aber nicht in einem Shader abtastet.
Typischer Einsatz: Man erzeugt einen Framebuffer, hängt eine Textur als Farb-Anhang an (COLOR_ATTACHMENT0) und einen Renderbuffer mit DEPTH_COMPONENT16 oder DEPTH_STENCIL als Tiefen-Anhang. So funktioniert der Tiefentest auch beim Rendern in eine Textur, z. B. bei Post-Processing, Picking oder Spiegelungen.
Ein erneuter Aufruf ersetzt den bisherigen Speicher komplett. Das nutzt man, wenn sich die Canvas-Größe ändert. Der Inhalt ist danach undefiniert (WebGL setzt ihn auf 0) und muss neu gerendert werden. Breite und Höhe dürfen gl.getParameter(gl.MAX_RENDERBUFFER_SIZE) nicht überschreiten.
In WebGL 2 stehen deutlich mehr Formate zur Verfügung, z. B. RGBA8, DEPTH24_STENCIL8 oder DEPTH_COMPONENT32F. Für Multisampling gibt es dort die Variante renderbufferStorageMultisample().
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $target Pflicht | GLenum | Muss gl.RENDERBUFFER sein. |
|
| $internalFormat Pflicht | GLenum | Internes Format des Speichers. In WebGL 1: gl.RGBA4, gl.RGB565, gl.RGB5_A1, gl.DEPTH_COMPONENT16, gl.STENCIL_INDEX8, gl.DEPTH_STENCIL. Mit Erweiterungen kommen weitere hinzu: EXT_sRGB liefert SRGB8_ALPHA8_EXT, WEBGL_color_buffer_float liefert RGBA32F_EXT. WebGL 2 ergänzt u. a. gl.RGBA8, gl.DEPTH24_STENCIL8, gl.DEPTH_COMPONENT24 und gl.DEPTH_COMPONENT32F. |
|
| $width Pflicht | GLsizei (number) | Breite in Pixeln, von 0 bis MAX_RENDERBUFFER_SIZE. |
|
| $height Pflicht | GLsizei (number) | Höhe in Pixeln, von 0 bis MAX_RENDERBUFFER_SIZE. |
Rückgabewert
undefined). Fehler meldet die Methode über gl.getError().Beispiele
Tiefenpuffer für Render-to-Texture
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const width = 512, height = 512;
// Farb-Anhang als Textur
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
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);
// Tiefen-Anhang als Renderbuffer
const depthRb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthRb);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 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: ' + status);
Renderbuffer bei Größenänderung neu anlegen
const gl = document.querySelector('canvas').getContext('webgl');
const depthRb = gl.createRenderbuffer();
const resize = () => {
const w = gl.canvas.clientWidth * devicePixelRatio | 0;
const h = gl.canvas.clientHeight * devicePixelRatio | 0;
const max = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE);
gl.canvas.width = Math.min(w, max);
gl.canvas.height = Math.min(h, max);
gl.bindRenderbuffer(gl.RENDERBUFFER, depthRb);
// Ersetzt den alten Speicher vollständig
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, gl.canvas.width, gl.canvas.height);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
console.log('Renderbuffer:', gl.getRenderbufferParameter(gl.RENDERBUFFER === 0 ? 0 : gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH) ?? 'ungebunden');
};
window.addEventListener('resize', resize);
resize();
WebGL 2: Depth24/Stencil8 und Größe abfragen
const gl = document.createElement('canvas').getContext('webgl2');
const rb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, 1024, 768);
console.log(
gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_WIDTH),
gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_HEIGHT),
gl.getError() === gl.NO_ERROR
);
// Wichtig · Fallstricke
- Vor dem Aufruf muss ein Renderbuffer gebunden sein. Sonst erzeugt die Methode
INVALID_OPERATION. - Ein ungültiges
targetoderinternalFormaterzeugtINVALID_ENUM. Eine negative Größe oder ein Wert überMAX_RENDERBUFFER_SIZEerzeugtINVALID_VALUE. Ist nicht genug Speicher frei, erzeugt sieOUT_OF_MEMORY. - Alle Anhänge eines Framebuffers sollten dieselbe Größe haben. Sonst meldet
checkFramebufferStatus()einen unvollständigen Framebuffer, z. B.FRAMEBUFFER_INCOMPLETE_DIMENSIONSin WebGL 1. - In WebGL 1 gilt: Den kombinierten Tiefen-/Stencil-Puffer
DEPTH_STENCILanDEPTH_STENCIL_ATTACHMENTanhängen, nicht getrennt an Tiefen- und Stencil-Anhang. - Einen Renderbuffer kann man im Shader nicht abtasten. Wenn man die Tiefe später auslesen will (z. B. für Shadow Mapping), braucht man eine Tiefentextur: in WebGL 2 nativ, in WebGL 1 über
WEBGL_depth_texture. - Nach einer Größenänderung ist der Inhalt verloren und muss neu gerendert werden. Den Aufruf nicht in jedem Frame wiederholen, weil jede neue Zuweisung Leistung kostet.
- Die Methode wird breit unterstützt, in allen modernen Browsern mit WebGL. Welche Formate verfügbar sind, hängt von der WebGL-Version und den aktivierten Erweiterungen ab.