Start · Sprachen · JavaScript · Referenz · WebGL2RenderingContext.texStorage2D()

WebGL2RenderingContext.texStorage2D()

Methode

Reserviert unveränderlichen Speicher für alle Mipmap-Ebenen einer 2D- oder Cubemap-Textur mit festem internem Format und fester Größe.

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

Signatur

WebGL2RenderingContext.prototype.texStorage2D(target, levels, internalformat, width, height)

Beschreibung

texStorage2D() legt in einem einzigen Aufruf den Speicher für alle Mipmap-Ebenen der aktuell gebundenen Textur an. Das Ergebnis ist eine unveränderliche Textur (immutable texture): Format, Größe und Anzahl der Ebenen stehen danach fest. Die Pixeldaten selbst werden anschließend mit texSubImage2D() oder compressedTexSubImage2D() hochgeladen oder per Framebuffer gerendert.

Im Vergleich zu mehrfachen texImage2D()-Aufrufen hat das zwei Vorteile: Der Treiber muss die Vollständigkeit der Textur nicht bei jedem Zeichenaufruf prüfen, und Fehler durch inkonsistente Ebenengrößen oder Formate sind ausgeschlossen. Daher ist texStorage2D() in WebGL 2 der empfohlene Weg, um Texturen – insbesondere Render-Targets und Mipmap-Texturen – anzulegen.

Als internalformat muss ein sized Format wie gl.RGBA8, gl.RGB565, gl.R32F, gl.DEPTH_COMPONENT24 oder ein komprimiertes Format angegeben werden. Unsized Formate wie gl.RGBA sind nicht erlaubt. Bei gl.TEXTURE_CUBE_MAP wird Speicher für alle sechs Seiten gleichzeitig reserviert; width und height müssen dann gleich sein.

Parameter

Name Typ Default Beschreibung
$target Pflicht GLenum Bindungsziel: gl.TEXTURE_2D oder gl.TEXTURE_CUBE_MAP.
$levels Pflicht GLsizei Anzahl der Mipmap-Ebenen (mindestens 1). Maximal Math.floor(Math.log2(Math.max(width, height))) + 1.
$internalformat Pflicht GLenum Sized internes Format, z. B. gl.RGBA8, gl.SRGB8_ALPHA8, gl.RGBA16F, gl.R8, gl.DEPTH_COMPONENT24, gl.DEPTH24_STENCIL8 oder ein komprimiertes Format aus einer Erweiterung.
$width Pflicht GLsizei Breite der Basisebene (Ebene 0) in Texeln.
$height Pflicht GLsizei Höhe der Basisebene (Ebene 0) in Texeln.

Rückgabewert

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

Beispiele

Textur mit Mipmaps anlegen und Bild hochladen

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

const loadTexture = async (url) => {
  const img = new Image();
  img.src = url;
  await img.decode();

  const levels = Math.floor(Math.log2(Math.max(img.width, img.height))) + 1;
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);

  // Unveränderlichen Speicher für alle Ebenen reservieren
  gl.texStorage2D(gl.TEXTURE_2D, levels, gl.RGBA8, img.width, img.height);
  // Ebene 0 befüllen, restliche Ebenen generieren
  gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, img);
  gl.generateMipmap(gl.TEXTURE_2D);

  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
  console.log('Ebenen:', gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_IMMUTABLE_LEVELS));
  return tex;
};

loadTexture('holz-512.png');
Ebenen: 10

Render-Target für Framebuffer (Farbe + Tiefe)

const gl = document.querySelector('canvas').getContext('webgl2');
const [w, h] = [1024, 768];

const color = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, color);
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, w, h);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

const depth = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, depth);
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.DEPTH_COMPONENT24, w, h);

const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, color, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depth, 0);

const ok = gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE;
console.log('Framebuffer vollständig:', ok);
Framebuffer vollständig: true

Cubemap mit Float-Daten und Fehlerprüfung

const gl = document.querySelector('canvas').getContext('webgl2');
const size = 64;

const cube = gl.createTexture();
gl.bindTexture(gl.TEXTURE_CUBE_MAP, cube);
// Speicher für alle 6 Seiten auf einmal
gl.texStorage2D(gl.TEXTURE_CUBE_MAP, 1, gl.RGBA16F, size, size);

const data = new Float32Array(size * size * 4).fill(0.5);
for (let face = 0; face < 6; face++) {
  gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, 0, 0,
    size, size, gl.RGBA, gl.FLOAT, data);
}

console.log('Fehler:', gl.getError() === gl.NO_ERROR ? 'keiner' : gl.getError());
Fehler: keiner

// Wichtig · Fallstricke

  • Unveränderlich: Ein zweiter Aufruf von texStorage2D() oder ein texImage2D() auf derselben Textur erzeugt INVALID_OPERATION. Zum Ändern der Größe (z. B. beim Canvas-Resize) muss die Textur gelöscht und neu angelegt werden.
  • Nur sized Formate: gl.RGBA als internalformat führt zu INVALID_ENUM. Das Format bei texSubImage2D() (format/type) muss zum internen Format passen, z. B. RGBA8 ↔ RGBA/UNSIGNED_BYTE.
  • Zu viele Ebenen (levels größer als log2(max)+1) oder levels/Größe < 1 führen zu INVALID_OPERATION bzw. INVALID_VALUE.
  • Float-Formate wie RGBA16F/RGBA32F sind als Render-Target nur mit der Erweiterung EXT_color_buffer_float nutzbar; lineares Filtern von RGBA32F erfordert OES_texture_float_linear.
  • Ist die Textur nicht vollständig mit Mipmaps befüllt, TEXTURE_MIN_FILTER auf LINEAR oder NEAREST setzen oder generateMipmap() aufrufen – sonst wird schwarz gesampelt.
  • Nur im WebGL-2-Kontext verfügbar. In WebGL 1 gibt es die Methode nicht (dort ggf. über Erweiterungen nicht standardisiert); Verfügbarkeit per canvas.getContext('webgl2') prüfen.