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

WebGLRenderingContext.compressedTexSubImage2D()

Methode

Überschreibt einen rechteckigen Teilbereich einer bereits angelegten Textur mit Bilddaten in einem komprimierten Format (z. B. S3TC, ETC, ASTC).

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

Signatur

WebGLRenderingContext.prototype.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, pixels)

Beschreibung

compressedTexSubImage2D() ersetzt einen Ausschnitt eines 2D-Texturbildes oder einer Cube-Map-Fläche durch neue, bereits komprimierte Bilddaten. Die Textur muss vorher mit compressedTexImage2D() (oder in WebGL 2 mit texStorage2D()) im gleichen komprimierten Format angelegt worden sein. Speicher wird dabei nicht neu belegt, es werden nur die Daten ausgetauscht.

Typische Einsatzfälle sind Streaming von Textur-Kacheln (Terrain, Karten, Megatexturen), das schrittweise Nachladen von Mip-Stufen oder das Aktualisieren von Atlanten, ohne die komplette Textur neu hochzuladen. Komprimierte Formate sparen GPU-Speicher und Bandbreite, weil die GPU die Blöcke direkt dekodiert.

Komprimierte Formate stehen nur über Erweiterungen zur Verfügung, z. B. WEBGL_compressed_texture_s3tc (Desktop), WEBGL_compressed_texture_etc, WEBGL_compressed_texture_astc oder EXT_texture_compression_bptc. Die Formatkonstante (etwa ext.COMPRESSED_RGBA_S3TC_DXT5_EXT) stammt aus dem jeweiligen Erweiterungsobjekt, das man mit gl.getExtension() erhält.

Da blockbasierte Formate in Blöcken (meist 4×4 Pixel) organisiert sind, müssen xoffset, yoffset, width und height in der Regel Vielfache der Blockgröße sein; die Byte-Länge von pixels muss exakt zur Größe des Bereichs passen.

Parameter

Name Typ Default Beschreibung
$target Pflicht GLenum Texturziel: 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; 0 ist das Basisbild.
$xoffset Pflicht GLint Horizontaler Versatz (in Texeln) des Teilbereichs; meist Vielfaches der Blockbreite (z. B. 4).
$yoffset Pflicht GLint Vertikaler Versatz (in Texeln) des Teilbereichs; meist Vielfaches der Blockhöhe.
$width Pflicht GLsizei Breite des Teilbereichs in Texeln.
$height Pflicht GLsizei Höhe des Teilbereichs in Texeln.
$format Pflicht GLenum Komprimiertes Format aus einer Erweiterung, z. B. ext.COMPRESSED_RGBA_S3TC_DXT5_EXT. Muss dem Format der bestehenden Textur entsprechen.
$pixels Pflicht ArrayBufferView Komprimierte Blockdaten (meist Uint8Array). In WebGL 2 alternativ ein Offset (GLintptr) in einen gebundenen PIXEL_UNPACK_BUFFER plus imageSize, bzw. zusätzliche Parameter srcOffset/srcLengthOverride.

Rückgabewert

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

Beispiele

Textur anlegen und eine 4×4-Kachel ersetzen (S3TC/DXT1)

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

if (!ext) {
  console.log('S3TC wird nicht unterstützt');
} else {
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);

  // DXT1: 8 Byte pro 4×4-Block -> 16×16 Textur = 16 Blöcke = 128 Byte
  const full = new Uint8Array(128);
  gl.compressedTexImage2D(gl.TEXTURE_2D, 0,
    ext.COMPRESSED_RGB_S3TC_DXT1_EXT, 16, 16, 0, full);

  // Einen Block (4×4 Texel) an Position (4, 8) ersetzen
  const block = new Uint8Array([0xff, 0xff, 0x00, 0x00, 0, 0, 0, 0]);
  gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 4, 8, 4, 4,
    ext.COMPRESSED_RGB_S3TC_DXT1_EXT, block);

  console.log(gl.getError() === gl.NO_ERROR ? 'OK' : 'Fehler');
}
OK

Kachel-Streaming: komprimierte Kachel nachladen

// Lädt eine vorkomprimierte DXT5-Kachel (z. B. 64×64) und schreibt sie in einen Atlas
const updateTile = async (gl, ext, atlasTex, url, tileX, tileY, size = 64) => {
  const response = await fetch(url);
  const data = new Uint8Array(await response.arrayBuffer());

  // DXT5: 16 Byte pro 4×4-Block
  const expected = (size / 4) * (size / 4) * 16;
  if (data.byteLength !== expected) {
    throw new Error(`Falsche Datenlänge: ${data.byteLength} statt ${expected}`);
  }

  gl.bindTexture(gl.TEXTURE_2D, atlasTex);
  gl.compressedTexSubImage2D(
    gl.TEXTURE_2D, 0,
    tileX * size, tileY * size, size, size,
    ext.COMPRESSED_RGBA_S3TC_DXT5_EXT,
    data
  );
};

// Aufruf: await updateTile(gl, ext, atlas, '/tiles/3_2.dxt5', 3, 2);

WebGL 2: Upload aus einem Pixel-Unpack-Buffer

const gl = document.createElement('canvas').getContext('webgl2');
const ext = gl.getExtension('WEBGL_compressed_texture_etc');

if (ext) {
  const fmt = ext.COMPRESSED_RGBA8_ETC2_EAC; // 16 Byte pro Block
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  gl.texStorage2D(gl.TEXTURE_2D, 1, fmt, 32, 32);

  const pbo = gl.createBuffer();
  gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo);
  const bytes = (8 / 4) * (8 / 4) * 16; // 8×8-Bereich = 64 Byte
  gl.bufferData(gl.PIXEL_UNPACK_BUFFER, new Uint8Array(bytes), gl.STATIC_DRAW);

  // Signatur mit imageSize und Offset in den gebundenen Buffer
  gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 8, 8, 8, 8, fmt, bytes, 0);
  gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
  console.log(gl.getError());
}