Signatur
Beschreibung
compressedTexSubImage3D() schreibt komprimierte Bilddaten in einen quaderförmigen Teilbereich einer bereits angelegten Textur vom Typ gl.TEXTURE_2D_ARRAY oder gl.TEXTURE_3D. Anders als compressedTexImage3D() reserviert die Methode keinen neuen Speicher, sondern ersetzt nur die Texel im angegebenen Bereich. Die Textur muss deshalb vorher mit texStorage3D() oder compressedTexImage3D() im gleichen komprimierten internen Format angelegt worden sein.
Typisch ist die Methode für Textur-Arrays bei Terrain, Sprite-Atlanten oder Material-Bibliotheken, deren einzelne Ebenen nachgeladen oder ausgetauscht werden (Streaming). Die Daten bleiben auf der Grafikkarte komprimiert. Das spart Grafikspeicher und Bandbreite beim Hochladen.
Es gibt zwei Aufrufvarianten:
- Quelldaten aus dem Arbeitsspeicher:
srcDataist einArrayBufferView, optional mitsrcOffset(in Elementen) undsrcLengthOverride. - Aus einem
PIXEL_UNPACK_BUFFER: Ist ein solcher Puffer gebunden, lautet die Signatur(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, offset). Die Daten werden dann direkt aus dem GPU-Puffer ab dem Byte-Offsetoffsetgelesen.
Welche komprimierten Formate zur Verfügung stehen, hängt von den Erweiterungen ab, die das Gerät unterstützt, z. B. WEBGL_compressed_texture_s3tc (Desktop), WEBGL_compressed_texture_etc (mobil) oder WEBGL_compressed_texture_astc. Die Erweiterung muss mit getExtension() aktiviert werden, bevor ihre Formatkonstanten gültig sind.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $target Pflicht | GLenum | — | Ziel der Textur: gl.TEXTURE_2D_ARRAY oder gl.TEXTURE_3D. Hinweis: Viele Blockformate (z. B. S3TC, ETC2) sind für TEXTURE_3D nicht erlaubt, nur für TEXTURE_2D_ARRAY. |
| $level Pflicht | GLint | — | Mipmap-Stufe, 0 ist das Basisbild. |
| $xoffset Pflicht | GLint | — | Horizontaler Texel-Versatz. Muss ein Vielfaches der Blockbreite sein (bei S3TC/ETC2 also 4). |
| $yoffset Pflicht | GLint | — | Vertikaler Texel-Versatz. Muss ein Vielfaches der Blockhöhe sein. |
| $zoffset Pflicht | GLint | — | Versatz in der Tiefe bzw. Index der ersten Array-Ebene. |
| $width Pflicht | GLsizei | — | Breite des Teilbereichs in Texeln. Muss ein Vielfaches der Blockbreite sein, außer der Bereich reicht bis zum Texturrand. |
| $height Pflicht | GLsizei | — | Höhe des Teilbereichs in Texeln, Regeln wie bei width. |
| $depth Pflicht | GLsizei | — | Tiefe bzw. Anzahl der zu überschreibenden Array-Ebenen. |
| $format Pflicht | GLenum | — | Komprimiertes Format, z. B. ext.COMPRESSED_RGBA_S3TC_DXT5_EXT, gl.COMPRESSED_RGBA8_ETC2_EAC oder ext.COMPRESSED_RGBA_ASTC_4x4_KHR. Muss dem internen Format der Textur entsprechen. |
| $srcData Pflicht | ArrayBufferView | — | Komprimierte Blockdaten, meist ein Uint8Array. Entfällt in der PBO-Variante zugunsten von imageSize und offset. |
| $srcOffset | GLuint | 0 | Startindex (in Elementen des Views) innerhalb von srcData. |
| $srcLengthOverride | GLuint | 0 | Anzahl der zu lesenden Elemente. Bei 0 wird bis zum Ende von srcData gelesen. |
| $imageSize | GLsizei | — | Nur PBO-Variante: Datengröße in Bytes. |
| $offset | GLintptr | — | Nur PBO-Variante: Byte-Offset im gebundenen PIXEL_UNPACK_BUFFER. |
Rückgabewert
gl.getError() gemeldet (z. B. INVALID_OPERATION bei falschem Format oder unpassender Datengröße).Beispiele
Einzelne Ebene eines S3TC-Textur-Arrays austauschen
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2');
const ext = gl.getExtension('WEBGL_compressed_texture_s3tc');
if (!ext) throw new Error('S3TC wird nicht unterstützt');
const size = 256;
const layers = 8;
const format = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D_ARRAY, tex);
// Unveränderlichen Speicher für 8 Ebenen anlegen
gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, format, size, size, layers);
// DXT5: 16 Bytes pro 4×4-Block
const bytesPerLayer = (size / 4) * (size / 4) * 16;
const layerData = new Uint8Array(bytesPerLayer); // hier echte Blockdaten laden
// Ebene 3 vollständig überschreiben
gl.compressedTexSubImage3D(
gl.TEXTURE_2D_ARRAY, 0,
0, 0, 3, // x, y, z (Ebene)
size, size, 1, // Breite, Höhe, Tiefe
format, layerData
);
console.log(gl.getError() === gl.NO_ERROR);
Mehrere Ebenen aus einer Datei streamen (srcOffset)
const loadLayers = async (gl, tex, format, url, size, firstLayer, count) => {
const buf = new Uint8Array(await (await fetch(url)).arrayBuffer());
const bytesPerLayer = Math.ceil(size / 4) * Math.ceil(size / 4) * 16;
gl.bindTexture(gl.TEXTURE_2D_ARRAY, tex);
for (let i = 0; i < count; i++) {
gl.compressedTexSubImage3D(
gl.TEXTURE_2D_ARRAY, 0,
0, 0, firstLayer + i,
size, size, 1,
format,
buf,
i * bytesPerLayer, // srcOffset in Elementen (hier Bytes)
bytesPerLayer // srcLengthOverride
);
}
};
// Aufruf: 4 Terrain-Ebenen ab Ebene 2 laden
// await loadLayers(gl, tex, gl.COMPRESSED_RGBA8_ETC2_EAC, '/terrain.etc2', 512, 2, 4);
Upload über einen PIXEL_UNPACK_BUFFER
const format = gl.COMPRESSED_RGBA8_ETC2_EAC; // ETC2 ist in WebGL2 u. U. per Erweiterung verfügbar
const size = 128;
const bytes = (size / 4) * (size / 4) * 16;
const data = new Uint8Array(bytes);
const pbo = gl.createBuffer();
gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo);
gl.bufferData(gl.PIXEL_UNPACK_BUFFER, data, gl.STATIC_DRAW);
gl.bindTexture(gl.TEXTURE_2D_ARRAY, tex);
// PBO-Variante: imageSize und Byte-Offset statt ArrayBufferView
gl.compressedTexSubImage3D(
gl.TEXTURE_2D_ARRAY, 0,
0, 0, 0,
size, size, 1,
format, bytes, 0
);
// Puffer wieder lösen, sonst schlagen spätere Uploads mit ArrayBufferView fehl
gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);