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

WebGLRenderingContext.copyTexSubImage2D()

Methode

Kopiert einen rechteckigen Pixelbereich aus dem aktuell gebundenen Framebuffer in einen Teilbereich einer bereits angelegten 2D-Textur.

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

Signatur

WebGLRenderingContext.prototype.copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height)

Beschreibung

copyTexSubImage2D() liest Pixel aus dem aktuell gebundenen Lese-Framebuffer (standardmäßig der Zeichenpuffer des Canvas, sonst ein per bindFramebuffer() gebundenes WebGLFramebuffer) und schreibt sie in einen Ausschnitt der Textur, die gerade an target gebunden ist. Die Kopie läuft komplett auf der GPU, die Daten gehen also nicht über den Umweg zur CPU wie bei readPixels().

Anders als copyTexImage2D() legt die Methode keinen neuen Texturspeicher an. Die Textur muss vorher mit texImage2D() (oder copyTexImage2D()) in ausreichender Größe angelegt worden sein. Deshalb eignet sich die Methode gut, um Texturen immer wieder teilweise zu aktualisieren, ohne sie neu anzulegen. Typische Anwendungen sind Feedback-Effekte (Bewegungsunschärfe, Nachzieheffekte), Snapshots der Szene für Nachbearbeitung, Spiegelungen oder das Füllen eines Textur-Atlas.

Das Quellrechteck wird durch x, y, width und height im Framebuffer beschrieben (Ursprung unten links), das Ziel durch xoffset/yoffset in der Textur. Liegen Teile des Quellrechtecks außerhalb des Framebuffers, sind die entsprechenden Texel in WebGL mit 0 gefüllt.

Parameter

Name Typ Default Beschreibung
$target Pflicht GLenum Textur-Ziel: gl.TEXTURE_2D oder eine Cube-Map-Fläche wie gl.TEXTURE_CUBE_MAP_POSITIVE_X … gl.TEXTURE_CUBE_MAP_NEGATIVE_Z.
$level Pflicht GLint Mipmap-Stufe, in die geschrieben wird. 0 ist das Basisbild.
$xoffset Pflicht GLint Horizontaler Versatz (in Texeln) innerhalb der Zieltextur.
$yoffset Pflicht GLint Vertikaler Versatz (in Texeln) innerhalb der Zieltextur.
$x Pflicht GLint X-Koordinate der unteren linken Ecke des Quellrechtecks im Framebuffer.
$y Pflicht GLint Y-Koordinate der unteren linken Ecke des Quellrechtecks im Framebuffer (Ursprung unten).
$width Pflicht GLsizei Breite des zu kopierenden Bereichs in Pixeln.
$height Pflicht GLsizei Höhe des zu kopierenden Bereichs in Pixeln.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert. Fehler werden über gl.getError() gemeldet (z. B. INVALID_VALUE, INVALID_OPERATION, INVALID_FRAMEBUFFER_OPERATION).

Beispiele

Canvas-Inhalt in eine vorhandene Textur kopieren

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

// Textur einmalig in Canvas-Größe anlegen (ohne Daten)
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.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);

// Etwas zeichnen – hier nur eine Füllfarbe
gl.clearColor(0.2, 0.4, 0.8, 1);
gl.clear(gl.COLOR_BUFFER_BIT);

// Gesamten Zeichenpuffer in die Textur kopieren
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, canvas.width, canvas.height);
console.log(gl.getError() === gl.NO_ERROR);
true

Ausschnitt aus einem Framebuffer in einen Textur-Atlas schreiben

const gl = document.createElement('canvas').getContext('webgl');

// Quelle: Offscreen-Framebuffer mit 128×128-Farbtextur
const srcTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, srcTex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 128, 128, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
const fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, srcTex, 0);

gl.clearColor(1, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);

// Ziel: 256×256-Atlas
const atlas = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, atlas);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 256, 256, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

// 64×64-Bereich ab (32,32) im Framebuffer nach (128,0) im Atlas kopieren
gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 128, 0, 32, 32, 64, 64);

gl.bindFramebuffer(gl.FRAMEBUFFER, null);
console.log(gl.getError());

Feedback-Effekt: letztes Bild pro Frame sichern

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl', { preserveDrawingBuffer: false });

const history = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, history);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, canvas.width, canvas.height, 0,
  gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

const drawScene = (t) => {
  gl.clearColor(Math.sin(t / 1000) * 0.5 + 0.5, 0.2, 0.3, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
  // … hier würde die Szene die Textur 'history' überblenden …
};

const frame = (t) => {
  drawScene(t);
  // Ergebnis für den nächsten Frame sichern – noch im selben Frame!
  gl.bindTexture(gl.TEXTURE_2D, history);
  gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, canvas.width, canvas.height);
  requestAnimationFrame(frame);
};
requestAnimationFrame(frame);