Start · Sprachen · JavaScript · Referenz · WEBGL_compressed_texture_s3tc extension

WEBGL_compressed_texture_s3tc extension

Schnittstelle

WebGL-Erweiterung, die vier S3TC-Formate (DXT1 RGB/RGBA, DXT3, DXT5) für <code>compressedTexImage2D()</code> bereitstellt.

seit JavaScript WebGL 1 / WebGL 2 – Erweiterung; breit unterstützt Kategorie: webapi

Signatur

interface WEBGL_compressed_texture_s3tc

Beschreibung

Die Erweiterung WEBGL_compressed_texture_s3tc gehört zur WebGL-API und macht die S3TC-Kompression verfügbar, die auch als DXTn bzw. BC1–BC3 bekannt ist. Mit ihr lädt man vorab komprimierte Texturdaten (meist aus .dds- oder .ktx-Dateien) direkt auf die GPU. Die Textur bleibt auch im Grafikspeicher komprimiert. Sie braucht dadurch 4- bis 8-mal weniger VRAM als eine unkomprimierte RGBA-Textur, lädt schneller und belastet beim Sampling die Speicherbandbreite weniger.

Aktiviert wird die Erweiterung mit gl.getExtension("WEBGL_compressed_texture_s3tc"). Man bekommt entweder ein Objekt mit vier Formatkonstanten zurück oder null, wenn der Browser bzw. die GPU sie nicht unterstützt. Die Konstanten übergibt man als internalformat an gl.compressedTexImage2D() und gl.compressedTexSubImage2D(), in WebGL 2 außerdem an gl.texStorage2D(). Welche Formate gerade aktiv sind, liefert zusätzlich gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS).

  • COMPRESSED_RGB_S3TC_DXT1_EXT (0x83F0): 8 Byte pro 4×4-Block, ohne Alphakanal. Gut für deckende Farbtexturen.
  • COMPRESSED_RGBA_S3TC_DXT1_EXT (0x83F1): 8 Byte pro Block mit 1-Bit-Alpha. Ein Pixel ist also entweder voll deckend oder voll transparent.
  • COMPRESSED_RGBA_S3TC_DXT3_EXT (0x83F2): 16 Byte pro Block mit explizitem 4-Bit-Alpha. Geeignet für scharfe Alphaübergänge.
  • COMPRESSED_RGBA_S3TC_DXT5_EXT (0x83F3): 16 Byte pro Block mit interpoliertem Alpha. Geeignet für weiche Verläufe wie Rauch oder Laub.

S3TC ist vor allem auf Desktop-GPUs verbreitet. Für plattformübergreifende Anwendungen liefert man die Texturen deshalb meist in mehreren Formaten aus, z. B. S3TC, ETC2 und ASTC, oder man nutzt Basis Universal/KTX2 und transkodiert zur Laufzeit in das Format, das die jeweilige GPU unterstützt.

Rückgabewert

Typ
WEBGL_compressed_texture_s3tc | null
Beschreibung
gl.getExtension() liefert ein Objekt mit den Konstanten COMPRESSED_RGB_S3TC_DXT1_EXT, COMPRESSED_RGBA_S3TC_DXT1_EXT, COMPRESSED_RGBA_S3TC_DXT3_EXT und COMPRESSED_RGBA_S3TC_DXT5_EXT – oder null, wenn die Erweiterung nicht unterstützt wird.

Beispiele

Erweiterung aktivieren und Formate prüfen

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

const s3tc = gl.getExtension('WEBGL_compressed_texture_s3tc');

if (!s3tc) {
  console.log('S3TC nicht verfügbar – Fallback auf ETC2/ASTC oder PNG');
} else {
  console.log(s3tc.COMPRESSED_RGBA_S3TC_DXT5_EXT.toString(16));
  // Aktive komprimierte Formate abfragen
  const formats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
  console.log(formats.includes(s3tc.COMPRESSED_RGBA_S3TC_DXT5_EXT));
}
83f3 true

DXT5-Textur aus einer DDS-Datei hochladen (inkl. Mipmaps)

const loadDDS = async (gl, url) => {
  const ext = gl.getExtension('WEBGL_compressed_texture_s3tc');
  if (!ext) throw new Error('S3TC nicht unterstützt');

  const buffer = await (await fetch(url)).arrayBuffer();
  const header = new Int32Array(buffer, 0, 31);
  if (header[0] !== 0x20534444) throw new Error('Keine DDS-Datei'); // 'DDS '

  const height = header[3];
  const width = header[4];
  const mipCount = Math.max(1, header[7]);
  const fourCC = header[21];
  const FOURCC = { DXT1: 0x31545844, DXT3: 0x33545844, DXT5: 0x35545844 };

  const [format, blockBytes] =
    fourCC === FOURCC.DXT1 ? [ext.COMPRESSED_RGBA_S3TC_DXT1_EXT, 8] :
    fourCC === FOURCC.DXT3 ? [ext.COMPRESSED_RGBA_S3TC_DXT3_EXT, 16] :
    fourCC === FOURCC.DXT5 ? [ext.COMPRESSED_RGBA_S3TC_DXT5_EXT, 16] :
    (() => { throw new Error('Unbekanntes FourCC'); })();

  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);

  let offset = 128; // DDS-Header: 4 Byte Magic + 124 Byte Header
  let w = width, h = height;
  for (let level = 0; level < mipCount; level++) {
    const size = Math.max(1, Math.ceil(w / 4)) * Math.max(1, Math.ceil(h / 4)) * blockBytes;
    const data = new Uint8Array(buffer, offset, size);
    gl.compressedTexImage2D(gl.TEXTURE_2D, level, format, 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);
  return tex;
};

const gl = document.querySelector('canvas').getContext('webgl');
const texture = await loadDDS(gl, '/textures/crate_dxt5.dds');
console.log(gl.getError() === gl.NO_ERROR);
true

WebGL 2: Speicher mit texStorage2D reservieren und Teilbereich aktualisieren

const gl = document.querySelector('canvas').getContext('webgl2');
const ext = gl.getExtension('WEBGL_compressed_texture_s3tc');

if (ext) {
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  // Unveränderlicher Speicher: 256×256, 1 Mip-Level, DXT1 ohne Alpha
  gl.texStorage2D(gl.TEXTURE_2D, 1, ext.COMPRESSED_RGB_S3TC_DXT1_EXT, 256, 256);

  // 64×64-Kachel = 16×16 Blöcke à 8 Byte = 2048 Byte
  const tile = new Uint8Array(16 * 16 * 8); // hier: schwarze Blöcke
  gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 64, 64, 64, 64,
    ext.COMPRESSED_RGB_S3TC_DXT1_EXT, tile);

  console.log(gl.getError() === gl.NO_ERROR);
}
true