Start · Sprachen · JavaScript · Referenz · WebGL2RenderingContext.renderbufferStorageMultisample()

WebGL2RenderingContext.renderbufferStorageMultisample()

Methode

Legt den Datenspeicher des gebundenen Renderbuffers mit Format, Größe und einer Anzahl Multisample-Abtastwerte (MSAA) an und initialisiert ihn.

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

Signatur

WebGL2RenderingContext.prototype.renderbufferStorageMultisample(target, samples, internalFormat, width, height)

Beschreibung

renderbufferStorageMultisample() ist die Multisample-Variante von renderbufferStorage(). Die Methode reserviert GPU-Speicher für den Renderbuffer, der gerade an gl.RENDERBUFFER gebunden ist. Dabei gibt man an, wie viele Abtastwerte (Samples) pro Pixel gespeichert werden sollen. Das ist die Grundlage für Multisample-Anti-Aliasing (MSAA) beim Rendern in eigene Framebuffer.

Das ist vor allem dann nötig, wenn man offscreen rendert, zum Beispiel für Post-Processing, Schattenkarten oder Render-to-Texture. Die Option antialias: true beim Erstellen des Kontexts glättet nämlich nur den Standard-Framebuffer. Ein Framebuffer mit Multisample-Anhängen lässt sich nicht direkt als Textur auslesen. Man rendert deshalb zuerst in den MSAA-Renderbuffer und löst das Ergebnis danach mit blitFramebuffer() in einen normalen Framebuffer mit Textur auf („resolve“).

Der Wert von samples darf höchstens gl.getParameter(gl.MAX_SAMPLES) betragen. Bei 0 verhält sich die Methode genau wie renderbufferStorage(). Die tatsächliche Anzahl kann die Implementierung aufrunden. Mit gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_SAMPLES) lässt sie sich abfragen.

Parameter

Name Typ Default Beschreibung
$target Pflicht GLenum Ziel-Bindungspunkt. Muss gl.RENDERBUFFER sein.
$samples Pflicht GLsizei (number) Anzahl der Abtastwerte pro Pixel. Erlaubt ist 0 bis gl.MAX_SAMPLES. Bei Integer-Formaten ist nur 0 erlaubt.
$internalFormat Pflicht GLenum Internes Format, z. B. gl.RGBA8, gl.RGB565, gl.SRGB8_ALPHA8, gl.DEPTH_COMPONENT24, gl.DEPTH24_STENCIL8, gl.DEPTH32F_STENCIL8 oder gl.STENCIL_INDEX8. Mit der Erweiterung EXT_color_buffer_float kommen auch gl.RGBA16F und gl.RGBA32F hinzu.
$width Pflicht GLsizei (number) Breite in Pixeln. Darf höchstens gl.MAX_RENDERBUFFER_SIZE betragen.
$height Pflicht GLsizei (number) Höhe in Pixeln. Darf höchstens gl.MAX_RENDERBUFFER_SIZE betragen.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Fehler werden über gl.getError() gemeldet.

Beispiele

MSAA-Farb- und Tiefenpuffer anlegen

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2');
const { width, height } = canvas;

// Gewünschte Sample-Zahl auf das Maximum der Hardware begrenzen
const samples = Math.min(4, gl.getParameter(gl.MAX_SAMPLES));

const colorRb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, colorRb);
gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.RGBA8, width, height);

const depthRb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthRb);
gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.DEPTH24_STENCIL8, width, height);

const msaaFbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, msaaFbo);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorRb);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthRb);

console.log(gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE);
true

MSAA-Ergebnis in eine Textur auflösen (Resolve per blitFramebuffer)

// Voraussetzung: gl, width, height, msaaFbo aus dem vorherigen Beispiel
const resolveTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, resolveTex);
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, width, height);

const resolveFbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, resolveFbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, resolveTex, 0);

const renderFrame = () => {
  // 1. Szene in den Multisample-Framebuffer zeichnen
  gl.bindFramebuffer(gl.FRAMEBUFFER, msaaFbo);
  gl.viewport(0, 0, width, height);
  gl.clearColor(0.1, 0.1, 0.1, 1);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  // ... gl.drawArrays(...) ...

  // 2. Multisample-Daten in die Textur auflösen
  gl.bindFramebuffer(gl.READ_FRAMEBUFFER, msaaFbo);
  gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, resolveFbo);
  gl.blitFramebuffer(0, 0, width, height, 0, 0, width, height,
    gl.COLOR_BUFFER_BIT, gl.NEAREST);

  // resolveTex kann jetzt z. B. im Post-Processing-Shader genutzt werden
  requestAnimationFrame(renderFrame);
};
requestAnimationFrame(renderFrame);

Tatsächliche Sample-Zahl prüfen und bei Größenänderung neu anlegen

const resizeMsaa = (gl, rb, samples, w, h) => {
  gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
  // Erneuter Aufruf ersetzt den bisherigen Speicher
  gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.RGBA8, w, h);
  const actual = gl.getRenderbufferParameter(gl.RENDERBUFFER, gl.RENDERBUFFER_SAMPLES);
  if (gl.getError() !== gl.NO_ERROR) console.warn('Speicher konnte nicht angelegt werden');
  return actual;
};

const gl = document.createElement('canvas').getContext('webgl2');
const rb = gl.createRenderbuffer();
console.log('Samples:', resizeMsaa(gl, rb, 4, 1280, 720));
Samples: 4