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

WebGLRenderingContext.generateMipmap()

Methode

Erzeugt für die aktuell gebundene Textur automatisch alle Mipmap-Stufen aus der Basisstufe (Level 0).

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

Signatur

WebGLRenderingContext.prototype.generateMipmap(target)

Beschreibung

Mit generateMipmap() berechnet WebGL aus dem Bild der Basisstufe (Level 0) der gerade an target gebundenen Textur alle kleineren Mipmap-Stufen. Jede Stufe ist halb so breit und halb so hoch wie die vorherige, bis 1×1 Pixel erreicht sind. Die Stufen werden auf der GPU erzeugt. Das geht in der Regel viel schneller, als jede Stufe selbst mit texImage2D() hochzuladen.

Mipmaps braucht man vor allem, wenn Texturen verkleinert, schräg oder weit entfernt dargestellt werden, etwa bei Böden, Geländeoberflächen oder Objekten in der Tiefe. Ohne Mipmaps entstehen Flimmern und Moiré-Muster. Außerdem sinkt mit Mipmaps die Speicherbandbreite, weil der Sampler auf kleinere Stufen zugreift. Mipmaps werden nur verwendet, wenn der Verkleinerungsfilter TEXTURE_MIN_FILTER auf einen *_MIPMAP_*-Modus steht, z. B. gl.LINEAR_MIPMAP_LINEAR (trilineare Filterung).

Rufe die Methode nach dem Hochladen der Basisstufe auf, also nach texImage2D() oder texSubImage2D(). Wenn sich die Basisstufe ändert, musst du sie erneut aufrufen. Das ist z. B. bei Videotexturen der Fall, sofern du dort überhaupt Mipmaps verwendest. In WebGL 1 muss die Textur Seitenlängen haben, die eine Zweierpotenz sind (Power of Two, z. B. 256×512). In WebGL 2 (WebGL2RenderingContext) fällt diese Einschränkung weg.

Parameter

Name Typ Default Beschreibung
$target Pflicht GLenum Das Texturziel, dessen gebundene Textur Mipmaps erhalten soll. In WebGL 1: gl.TEXTURE_2D oder gl.TEXTURE_CUBE_MAP. In WebGL 2 zusätzlich: gl.TEXTURE_3D oder gl.TEXTURE_2D_ARRAY.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Fehler werden nicht als Ausnahme geworfen, sondern über gl.getError() gemeldet.

Beispiele

Bild laden und Mipmaps erzeugen

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

const isPowerOf2 = (v) => (v & (v - 1)) === 0;

const loadTexture = (url) => new Promise((resolve, reject) => {
  const img = new Image();
  img.crossOrigin = 'anonymous';
  img.onload = () => {
    const tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, tex);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);

    if (isPowerOf2(img.width) && isPowerOf2(img.height)) {
      // Basisstufe ist hochgeladen -> jetzt Mipmaps berechnen
      gl.generateMipmap(gl.TEXTURE_2D);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
    } else {
      // WebGL 1: Nicht-Zweierpotenz-Texturen ohne Mipmaps und mit CLAMP_TO_EDGE
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    }
    resolve(tex);
  };
  img.onerror = reject;
  img.src = url;
});

const texture = await loadTexture('textures/boden-512.png');
console.log(gl.getError() === gl.NO_ERROR);
true

Fehler bei Nicht-Zweierpotenz-Texturen in WebGL 1 erkennen

const gl = document.createElement('canvas').getContext('webgl');
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);

// 300×200 ist keine Zweierpotenz
const pixels = new Uint8Array(300 * 200 * 4).fill(255);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 300, 200, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

gl.generateMipmap(gl.TEXTURE_2D);
const err = gl.getError();
console.log(err === gl.INVALID_OPERATION ? 'INVALID_OPERATION' : err);
INVALID_OPERATION

Cube-Map mit Mipmaps (Skybox / Umgebungsspiegelung)

const gl = document.querySelector('canvas').getContext('webgl2');
const size = 256;
const faces = [
  gl.TEXTURE_CUBE_MAP_POSITIVE_X, gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
  gl.TEXTURE_CUBE_MAP_POSITIVE_Y, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
  gl.TEXTURE_CUBE_MAP_POSITIVE_Z, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
];

const cube = gl.createTexture();
gl.bindTexture(gl.TEXTURE_CUBE_MAP, cube);

faces.forEach((face, i) => {
  const data = new Uint8Array(size * size * 4).fill(i * 40);
  gl.texImage2D(face, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
});

// Alle sechs Seiten müssen vollständig und quadratisch gleich groß sein
gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
console.log('Mipmap-Stufen:', Math.log2(size) + 1);
Mipmap-Stufen: 9

// Wichtig · Fallstricke

  • Zweierpotenz in WebGL 1: Hat die Basisstufe keine Seitenlängen, die Zweierpotenzen sind, erzeugt der Aufruf den Fehler INVALID_OPERATION. Eine solche Textur wird außerdem schwarz dargestellt, wenn ein Mipmap-Filter oder REPEAT eingestellt ist. In WebGL 2 gilt diese Einschränkung nicht.
  • Reihenfolge: Rufe die Methode erst nach texImage2D() auf. Wird sie vor dem Hochladen aufgerufen oder ist keine Textur gebunden, meldet WebGL INVALID_OPERATION.
  • Cube-Maps: Alle sechs Seiten müssen quadratisch sein und dieselbe Größe, dasselbe Format und denselben Typ haben. Sonst meldet WebGL INVALID_OPERATION.
  • Formate: Komprimierte Texturen (z. B. S3TC/ETC) und Tiefentexturen sind nicht erlaubt. In WebGL 2 muss das interne Format außerdem filterbar und als Renderziel nutzbar sein. Bei Formaten wie RGBA32F ist das ohne Erweiterungen wie OES_texture_float_linear bzw. EXT_color_buffer_float nicht der Fall.
  • Ungültiges target: Führt zu INVALID_ENUM.
  • Filter nicht vergessen: Der Standardwert von TEXTURE_MIN_FILTER ist NEAREST_MIPMAP_LINEAR. Eine Textur ohne vollständige Mipmap-Kette ist deshalb „unvollständig“ und wird schwarz dargestellt. Entweder du erzeugst Mipmaps, oder du stellst den Filter auf LINEAR/NEAREST.
  • Leistung: Mipmaps brauchen etwa 33 % zusätzlichen Grafikspeicher. Bei Texturen, die sich in jedem Frame ändern (Video, Canvas), kostet ein wiederholter Aufruf spürbar Leistung.
  • Kompatibilität: Wird von allen modernen Browsern mit WebGL-Unterstützung unterstützt. Die Methode gibt es auch in WebGL2RenderingContext.