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

WebGLRenderingContext.compressedTexImage2D()

Methode

Lädt ein zweidimensionales Texturbild in einem GPU-komprimierten Format (z. B. S3TC, ETC, ASTC) in die aktuell gebundene Textur.

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

Signatur

WebGLRenderingContext.prototype.compressedTexImage2D(target, level, internalformat, width, height, border, pixels)

Beschreibung

Mit compressedTexImage2D() übergeben Sie der GPU bereits komprimierte Texturdaten, die direkt im komprimierten Zustand im Grafikspeicher bleiben. Das spart Videospeicher und Bandbreite deutlich (typisch Faktor 4–8 gegenüber RGBA8) und ist daher in Spielen, 3D-Viewern und Kartenanwendungen mit vielen oder großen Texturen der Standardweg.

Die Daten werden nicht zur Laufzeit komprimiert – Sie müssen sie vorab mit Werkzeugen wie texconv, PVRTexTool, basisu oder toktx (KTX/KTX2, DDS) erzeugen. Welche Formate verfügbar sind, hängt von der Hardware ab und wird über Erweiterungen freigeschaltet, etwa WEBGL_compressed_texture_s3tc (Desktop), WEBGL_compressed_texture_etc, WEBGL_compressed_texture_astc oder WEBGL_compressed_texture_pvrtc (ältere iOS-Geräte). Die Format-Konstanten stammen aus dem jeweiligen Erweiterungsobjekt.

Jede Mipmap-Stufe wird mit einem eigenen Aufruf und passendem level hochgeladen. Für Teilaktualisierungen einer bestehenden komprimierten Textur verwenden Sie compressedTexSubImage2D(). In WebGL 2 existiert zusätzlich eine Überladung, die Daten aus einem gebundenen PIXEL_UNPACK_BUFFER liest (imageSize, offset) sowie Varianten mit srcOffset/srcLengthOverride.

Parameter

Name Typ Default Beschreibung
$target Pflicht GLenum — Bindungspunkt der Textur: gl.TEXTURE_2D oder eine Würfelseite wie gl.TEXTURE_CUBE_MAP_POSITIVE_X … gl.TEXTURE_CUBE_MAP_NEGATIVE_Z.
$level Pflicht GLint — Mipmap-Stufe; 0 ist das Basisbild, jede weitere Stufe halbiert Breite und Höhe.
$internalformat Pflicht GLenum — Komprimiertes Format aus einer Erweiterung, z. B. ext.COMPRESSED_RGBA_S3TC_DXT5_EXT, ext.COMPRESSED_RGB8_ETC2 oder ext.COMPRESSED_RGBA_ASTC_4x4_KHR.
$width Pflicht GLsizei — Breite des Bildes in Texeln. Muss zum Blockformat passen (bei S3TC meist Vielfaches von 4 für Stufe 0).
$height Pflicht GLsizei — Höhe des Bildes in Texeln.
$border Pflicht GLint 0 Rahmenbreite – muss immer 0 sein.
$pixels Pflicht ArrayBufferView — Komprimierte Blockdaten, z. B. ein Uint8Array. Die Länge muss exakt der vom Format geforderten Bytegröße entsprechen.

Rückgabewert

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

Beispiele

Verfügbares Kompressionsformat ermitteln

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

// Erweiterungen in Reihenfolge der Präferenz prüfen
const formats = {
  astc: gl.getExtension('WEBGL_compressed_texture_astc'),
  s3tc: gl.getExtension('WEBGL_compressed_texture_s3tc'),
  etc: gl.getExtension('WEBGL_compressed_texture_etc'),
  etc1: gl.getExtension('WEBGL_compressed_texture_etc1')
};

const available = Object.entries(formats)
  .filter(([, ext]) => ext !== null)
  .map(([name]) => name);

console.log('Unterstützt:', available);
console.log(gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS));
Unterstützt: ['s3tc'] Uint32Array(4) [33776, 33777, 33778, 33779]

DXT5-Textur mit Mipmaps hochladen

const gl = document.querySelector('canvas').getContext('webgl');
const s3tc = gl.getExtension('WEBGL_compressed_texture_s3tc');
if (!s3tc) throw new Error('S3TC wird nicht unterstützt');

// DXT5: 16 Byte pro 4×4-Block
const dxt5Size = (w, h) => Math.ceil(w / 4) * Math.ceil(h / 4) * 16;

const uploadDxt5 = (buffer, width, height, mipCount) => {
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  let offset = 0;
  let w = width;
  let h = height;
  for (let level = 0; level < mipCount; level++) {
    const size = dxt5Size(w, h);
    const data = new Uint8Array(buffer, offset, size);
    gl.compressedTexImage2D(gl.TEXTURE_2D, level,
      s3tc.COMPRESSED_RGBA_S3TC_DXT5_EXT, w, h, 0, data);
    offset += size;
    w = Math.max(1, w >> 1);
    h = Math.max(1, h >> 1);
  }
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER,
    mipCount > 1 ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  console.log('Fehlercode:', gl.getError());
  return tex;
};

// Beispiel: 256×256 mit 9 Mip-Stufen (Daten hier nur Platzhalter)
let total = 0;
for (let s = 256; s >= 1; s >>= 1) total += dxt5Size(s, s);
const texture = uploadDxt5(new ArrayBuffer(total), 256, 256, 9);
Fehlercode: 0

Komprimierte Textur aus einer Datei laden (async)

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

const loadRawDxt1 = async (url, width, height) => {
  const response = await fetch(url);
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  const data = new Uint8Array(await response.arrayBuffer());

  // DXT1: 8 Byte pro 4×4-Block
  const expected = Math.ceil(width / 4) * Math.ceil(height / 4) * 8;
  if (data.byteLength < expected) throw new Error('Datei zu klein');

  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  gl.compressedTexImage2D(gl.TEXTURE_2D, 0,
    s3tc.COMPRESSED_RGB_S3TC_DXT1_EXT, width, height, 0,
    data.subarray(0, expected));
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  return tex;
};

const tex = await loadRawDxt1('/textures/stein_512.dxt1', 512, 512);
console.log(gl.isTexture(tex));
true