Signatur
Beschreibung
copyTexSubImage3D() liest einen rechteckigen Bereich aus dem aktuellen Lese-Framebuffer (gl.READ_FRAMEBUFFER bzw. dem Standard-Zeichenpuffer, wenn keiner gebunden ist). Die Pixel landen in einer bereits angelegten 3D-Textur (gl.TEXTURE_3D) oder 2D-Array-Textur (gl.TEXTURE_2D_ARRAY). Welche Schicht (Tiefe bzw. Array-Index) beschrieben wird, legt zoffset fest. Pro Aufruf wird immer genau eine Schicht beschrieben.
Die Methode eignet sich gut, um Render-Ergebnisse ohne Umweg über die CPU in Texturen abzulegen. Typische Einsätze sind Schatten-Kaskaden, Zeitverläufe (Frame-Historie) in einem Textur-Array oder Volumendaten, die man Schicht für Schicht per Rendering aufbaut. Die Daten bleiben dabei vollständig auf der GPU. Das ist deutlich schneller als readPixels() mit anschließendem texSubImage3D().
Der Speicher der Zieltextur muss vorher angelegt sein, etwa mit texStorage3D() oder texImage3D(). Anders als bei copyTexImage2D() gibt es keine Variante copyTexImage3D(), die Speicher reserviert. Das interne Format der Textur muss zum Farbformat des Lese-Framebuffers passen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $target Pflicht | GLenum | Textur-Ziel: gl.TEXTURE_3D oder gl.TEXTURE_2D_ARRAY. |
|
| $level Pflicht | GLint | Mipmap-Stufe, in die geschrieben wird (0 = Basisstufe). | |
| $xoffset Pflicht | GLint | Horizontaler Versatz in der Zieltextur (in Texeln). | |
| $yoffset Pflicht | GLint | Vertikaler Versatz in der Zieltextur (in Texeln). | |
| $zoffset Pflicht | GLint | Tiefen- bzw. Schichtindex in der Zieltextur, in den kopiert wird. | |
| $x Pflicht | GLint | X-Koordinate der unteren linken Ecke des Quellbereichs im Framebuffer. | |
| $y Pflicht | GLint | Y-Koordinate der unteren linken Ecke des Quellbereichs im Framebuffer (Ursprung unten links). | |
| $width Pflicht | GLsizei | Breite des zu kopierenden Bereichs in Pixeln. | |
| $height Pflicht | GLsizei | Höhe des zu kopierenden Bereichs in Pixeln. |
Rückgabewert
undefined). Fehler lassen sich mit gl.getError() abfragen.Beispiele
Canvas-Inhalt in Schicht 0 einer 2D-Array-Textur kopieren
const canvas = document.createElement('canvas');
canvas.width = canvas.height = 256;
const gl = canvas.getContext('webgl2');
// Etwas in den Standard-Framebuffer zeichnen
gl.clearColor(1, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// Array-Textur mit 4 Schichten anlegen
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D_ARRAY, tex);
gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, 256, 256, 4);
// Gesamten Zeichenpuffer in Schicht 0 kopieren
gl.copyTexSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, 0, 0, 256, 256);
console.log(gl.getError() === gl.NO_ERROR);
Frame-Historie: jedes Frame in eine andere Schicht schreiben
const gl = document.querySelector('canvas').getContext('webgl2');
const W = gl.drawingBufferWidth;
const H = gl.drawingBufferHeight;
const HISTORY = 8;
const history = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D_ARRAY, history);
gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, W, H, HISTORY);
gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
let frame = 0;
const loop = (t) => {
gl.clearColor(Math.sin(t / 500) * 0.5 + 0.5, 0.2, 0.4, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// Aktuelles Bild in die Ringpuffer-Schicht sichern
gl.bindTexture(gl.TEXTURE_2D_ARRAY, history);
gl.copyTexSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, frame % HISTORY, 0, 0, W, H);
frame++;
requestAnimationFrame(loop);
};
requestAnimationFrame(loop);
Ausschnitt aus einem Offscreen-Framebuffer in eine 3D-Textur kopieren
const gl = document.createElement('canvas').getContext('webgl2');
// Quelle: Framebuffer mit 128×128-Farbtextur
const srcTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, srcTex);
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 128, 128);
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, srcTex, 0);
gl.clearColor(0, 1, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
// Ziel: 64×64×16-Volumentextur
const vol = gl.createTexture();
gl.bindTexture(gl.TEXTURE_3D, vol);
gl.texStorage3D(gl.TEXTURE_3D, 1, gl.RGBA8, 64, 64, 16);
// 32×32-Ausschnitt ab (16,16) nach Tiefe 5, Position (8,8)
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
gl.copyTexSubImage3D(gl.TEXTURE_3D, 0, 8, 8, 5, 16, 16, 32, 32);
console.log(gl.getError());
// Wichtig · Fallstricke
- Speicher muss existieren: Die Zieltextur braucht vorher Speicher über
texStorage3D()odertexImage3D(). Sonst entstehtINVALID_OPERATION. Liegt der Zielbereich (xoffset + width,zoffsetusw.) außerhalb der Textur, gibt esINVALID_VALUE. - Formatverträglichkeit: Das interne Format der Textur muss zum Lese-Framebuffer passen. Ein Beispiel ist Ganzzahl nach Ganzzahl. Tiefen- und Stencil-Formate lassen sich nicht kopieren. Float-Framebuffer brauchen in der Regel die Erweiterung
EXT_color_buffer_float. - Feedback-Schleife: Ist dieselbe Textur-Schicht zugleich an den Lese-Framebuffer gebunden, ist das Ergebnis undefiniert bzw. führt zu
INVALID_OPERATION. - Pixel außerhalb des Framebuffers ergeben undefinierte Werte. Die y-Achse beginnt unten links.
- Beim Standard-Framebuffer mit
preserveDrawingBuffer: falsesollte die Kopie im selben Frame wie das Zeichnen geschehen. - Nur im
WebGL2RenderingContextverfügbar, nicht in WebGL 1. Wird von allen aktuellen Browsern unterstützt (Safari ab 15).