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

WebGLRenderingContext.framebufferTexture2D()

Methode

Hängt eine 2D-Textur oder eine Cubemap-Seite als Farb-, Tiefen- oder Stencil-Anhang an das aktuell gebundene <code>WebGLFramebuffer</code> an.

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

Signatur

WebGLRenderingContext.prototype.framebufferTexture2D(target, attachment, textarget, texture, level)

Beschreibung

Mit framebufferTexture2D() verbindest du eine Textur mit einem Anhangspunkt des Framebuffers, der gerade an target gebunden ist. Danach landen alle Zeichenbefehle nicht mehr auf dem Canvas, sondern direkt in dieser Textur. Das ist die Grundlage für Render-to-Texture: Post-Processing (Blur, Bloom), Shadow Maps, Picking per Farb-ID, Spiegelungen oder mehrstufige Berechnungen auf der GPU.

Der übliche Ablauf ist: Textur mit texImage2D(..., null) in passender Größe anlegen, Framebuffer mit createFramebuffer() erzeugen und mit bindFramebuffer() binden, dann framebufferTexture2D() aufrufen und mit checkFramebufferStatus() prüfen, ob der Framebuffer vollständig ist. Für den Tiefenpuffer nimmt man meistens ein Renderbuffer über framebufferRenderbuffer(), außer man will die Tiefe später im Shader auslesen (z. B. bei Shadow Maps). Dann braucht man eine Tiefentextur.

Mit textarget legst du fest, welche Art von Textur angehängt wird: gl.TEXTURE_2D für normale Texturen oder eine der sechs Seiten gl.TEXTURE_CUBE_MAP_POSITIVE_X … NEGATIVE_Z, wenn du in eine Cubemap renderst, etwa für dynamische Umgebungskarten.

Parameter

Name Typ Default Beschreibung
$target Pflicht GLenum — Framebuffer-Ziel. In WebGL 1 nur gl.FRAMEBUFFER; in WebGL 2 zusätzlich gl.DRAW_FRAMEBUFFER und gl.READ_FRAMEBUFFER (gl.FRAMEBUFFER entspricht dort DRAW_FRAMEBUFFER).
$attachment Pflicht GLenum — Anhangspunkt: gl.COLOR_ATTACHMENT0, gl.DEPTH_ATTACHMENT, gl.STENCIL_ATTACHMENT oder gl.DEPTH_STENCIL_ATTACHMENT. Mit WEBGL_draw_buffers bzw. in WebGL 2 auch COLOR_ATTACHMENT1 … COLOR_ATTACHMENT15.
$textarget Pflicht GLenum — Texturziel: gl.TEXTURE_2D oder eine Cubemap-Seite wie gl.TEXTURE_CUBE_MAP_POSITIVE_X bis gl.TEXTURE_CUBE_MAP_NEGATIVE_Z.
$texture Pflicht WebGLTexture | null — Die anzuhängende Textur. Mit null wird ein vorhandener Anhang wieder entfernt.
$level Pflicht GLint 0 Mipmap-Stufe, in die gerendert wird. In WebGL 1 muss sie 0 sein; WebGL 2 erlaubt auch höhere Stufen.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Fehler werden über gl.getError() gemeldet (z. B. INVALID_ENUM, INVALID_OPERATION, wenn kein Framebuffer gebunden ist, oder INVALID_VALUE bei einem ungültigen level).

Beispiele

Render-to-Texture: Farbtextur und Tiefen-Renderbuffer

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const width = 512, height = 512;

// Zieltextur ohne Pixeldaten anlegen
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);
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);

// Tiefenpuffer als Renderbuffer
const depthRb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthRb);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);

// Framebuffer zusammenbauen
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)}`);

// In die Textur rendern
gl.viewport(0, 0, width, height);
gl.clearColor(0.2, 0.4, 0.8, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

// Zurück zum Canvas, colorTex kann jetzt als Eingabe dienen
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, canvas.width, canvas.height);
Framebuffer vollständig

Tiefentextur für Shadow Mapping (WebGL 2)

const gl = document.querySelector('canvas').getContext('webgl2');
const size = 1024;

const depthTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, depthTex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT24, size, size, 0,
  gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

const shadowFbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, shadowFbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTex, 0);

// Keine Farbausgabe nötig
gl.drawBuffers([gl.NONE]);
gl.readBuffer(gl.NONE);

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

Alle sechs Seiten einer Cubemap rendern

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

const cubeTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeTex);
for (let i = 0; i < 6; i++) {
  gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA, size, size, 0,
    gl.RGBA, gl.UNSIGNED_BYTE, null);
}
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.viewport(0, 0, size, size);

const colors = [[1,0,0],[0,1,0],[0,0,1],[1,1,0],[0,1,1],[1,0,1]];
colors.forEach(([r, g, b], i) => {
  // Jeweils eine Seite anhängen und hineinzeichnen
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
    gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, cubeTex, 0);
  gl.clearColor(r, g, b, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
});

gl.bindFramebuffer(gl.FRAMEBUFFER, null);
console.log('Cubemap befüllt');
Cubemap befüllt