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

WebGL2RenderingContext.drawBuffers()

Methode

Legt fest, in welche Farbpuffer (Color Attachments) die Ausgaben des Fragment-Shaders geschrieben werden – Grundlage für Multiple Render Targets (MRT).

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

Signatur

WebGL2RenderingContext.prototype.drawBuffers(buffers)

Beschreibung

drawBuffers() bestimmt, welchen Farbpuffern die einzelnen Ausgabevariablen des Fragment-Shaders zugeordnet werden. Der Index im übergebenen Array entspricht dem layout(location = n) der out-Variablen im GLSL-ES-3.00-Shader. So kann ein einziger Zeichenaufruf gleichzeitig in mehrere Texturen schreiben (Multiple Render Targets, MRT).

Typische Anwendung ist Deferred Shading: Ein G-Buffer-Durchlauf schreibt Albedo, Normalen und Positionen in einem Schritt in verschiedene Texturen, die ein späterer Beleuchtungsdurchlauf ausliest. Auch Picking (Farbe + Objekt-ID) oder Post-Processing-Effekte mit mehreren Zwischenergebnissen nutzen die Methode.

Die Einstellung gehört zum aktuell gebundenen Framebuffer. Für einen eigenen Framebuffer (FBO) sind nur gl.NONE und gl.COLOR_ATTACHMENTi erlaubt, wobei Eintrag i entweder gl.COLOR_ATTACHMENTi oder gl.NONE sein muss. Für den Standard-Framebuffer (null) ist genau ein Eintrag zulässig: gl.BACK oder gl.NONE.

Parameter

Name Typ Default Beschreibung
$buffers Pflicht Array<GLenum> Liste der Zielpuffer. Erlaubt sind gl.NONE, gl.BACK (nur beim Standard-Framebuffer) und gl.COLOR_ATTACHMENT0 … gl.COLOR_ATTACHMENT15. Die Länge darf gl.MAX_DRAW_BUFFERS nicht überschreiten.

Rückgabewert

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

Beispiele

G-Buffer mit zwei Render Targets einrichten

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

const createTarget = () => {
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  return tex;
};

const albedoTex = createTarget();
const normalTex = createTarget();

const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, albedoTex, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, normalTex, 0);

// location 0 -> Attachment 0, location 1 -> Attachment 1
gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]);

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

Passender Fragment-Shader (GLSL ES 3.00)

const fragmentSource = `#version 300 es
precision highp float;
in vec3 vNormal;
in vec2 vUv;
uniform sampler2D uDiffuse;

layout(location = 0) out vec4 outAlbedo;
layout(location = 1) out vec4 outNormal;

void main() {
  outAlbedo = texture(uDiffuse, vUv);
  outNormal = vec4(normalize(vNormal) * 0.5 + 0.5, 1.0);
}`;

const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, fragmentSource);
gl.compileShader(shader);
console.log(gl.getShaderParameter(shader, gl.COMPILE_STATUS));
true

Attachment vorübergehend deaktivieren und Limit prüfen

console.log('Max. Draw Buffers:', gl.getParameter(gl.MAX_DRAW_BUFFERS));

gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
// Nur in Attachment 1 schreiben, Attachment 0 bleibt unverändert
gl.drawBuffers([gl.NONE, gl.COLOR_ATTACHMENT1]);

// Zurück zum Canvas: Standard-Framebuffer erlaubt nur BACK oder NONE
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.drawBuffers([gl.BACK]);

console.log(gl.getParameter(gl.DRAW_BUFFER0) === gl.BACK);
Max. Draw Buffers: 8 true

// Wichtig · Fallstricke

  • Reihenfolge ist fest: Eintrag i muss gl.COLOR_ATTACHMENTi oder gl.NONE sein. [gl.COLOR_ATTACHMENT1, gl.COLOR_ATTACHMENT0] führt zu INVALID_OPERATION.
  • Beim Standard-Framebuffer ist nur ein Array mit genau einem Element (gl.BACK oder gl.NONE) erlaubt, sonst INVALID_OPERATION.
  • Mehr Einträge als gl.MAX_DRAW_BUFFERS ergeben INVALID_VALUE. WebGL 2 garantiert mindestens 4; verbreitet sind 8.
  • Die Einstellung wird pro Framebuffer gespeichert – nach dem Binden eines anderen FBO gilt dessen eigene Konfiguration.
  • gl.clear() betrifft alle aktiven Draw Buffers; für einzelne Puffer eignen sich clearBufferfv() und ähnliche Methoden.
  • In WebGL 1 steht die Funktionalität nur über die Erweiterung WEBGL_draw_buffers (drawBuffersWEBGL()) zur Verfügung. WebGL 2 wird von allen aktuellen Browsern unterstützt, ältere Safari-Versionen (vor 15) jedoch nicht.