Start · Sprachen · JavaScript · Referenz · WebGLTexture

WebGLTexture

Schnittstelle

Undurchsichtiges WebGL-Objekt, das eine Textur auf der GPU repräsentiert: Bilddaten, Mipmaps und Sampling-Zustand wie Filter und Wrapping.

seit JavaScript Baseline: alle Browser (WebGL 1, WebGL 2) Kategorie: webapi

Signatur

interface WebGLTexture extends WebGLObject

Beschreibung

WebGLTexture steht für ein Texturobjekt, das im Speicher der Grafikkarte liegt. Das Objekt ist undurchsichtig: Es hat keine eigenen öffentlichen Methoden oder Eigenschaften und dient nur als Referenz (Handle), die du an Methoden von WebGLRenderingContext bzw. WebGL2RenderingContext übergibst.

Erzeugt wird eine Textur nicht mit new, sondern mit gl.createTexture(). Danach bindest du sie mit gl.bindTexture(target, texture) an ein Ziel wie gl.TEXTURE_2D oder gl.TEXTURE_CUBE_MAP (in WebGL 2 zusätzlich TEXTURE_3D und TEXTURE_2D_ARRAY). Alle weiteren Aufrufe beziehen sich dann auf die gebundene Textur, zum Beispiel texImage2D() zum Hochladen von Pixeldaten, texParameteri() für Filter und Wrapping oder generateMipmap().

Texturen brauchst du für alles, was Bilddaten auf Geometrie abbildet: Sprites, Materialien in 3D-Szenen, Schriftatlanten, Videos als Textur und auch Render-to-Texture-Techniken, bei denen du eine Textur über ein WebGLFramebuffer als Zeichenziel verwendest. Im Shader liest du sie über eine sampler2D-Uniform, die auf eine Textureinheit (gl.activeTexture(gl.TEXTURE0 + n)) zeigt.

Wenn du eine Textur nicht mehr brauchst, gibst du den GPU-Speicher mit gl.deleteTexture(texture) frei. Ob ein Wert überhaupt eine gültige Textur ist, prüfst du mit gl.isTexture(texture).

Rückgabewert

Typ
WebGLTexture
Beschreibung
Instanzen bekommst du nur über gl.createTexture(). Die Methode gibt null zurück, wenn der Kontext verloren gegangen ist.

Beispiele

Textur erzeugen und mit einem Platzhalter-Pixel füllen

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

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

// 1×1 blaues Pixel als Platzhalter, bis das echte Bild geladen ist
const pixel = new Uint8Array([0, 0, 255, 255]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixel);

console.log(texture instanceof WebGLTexture);
console.log(gl.isTexture(texture));
true true

Bild asynchron laden und als Textur hochladen

const loadTexture = async (gl, url) => {
  const img = new Image();
  img.crossOrigin = 'anonymous'; // nötig bei Bildern von fremden Origins (CORS)
  img.src = url;
  await img.decode();

  const texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);

  const isPowerOf2 = (v) => (v & (v - 1)) === 0;
  if (isPowerOf2(img.width) && isPowerOf2(img.height)) {
    gl.generateMipmap(gl.TEXTURE_2D);
  } else {
    // WebGL 1: Nicht-Zweierpotenz-Texturen brauchen CLAMP_TO_EDGE und keine Mipmaps
    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);
  }
  return texture;
};

const gl = document.querySelector('canvas').getContext('webgl');
const tex = await loadTexture(gl, '/img/kiste.png');
console.log('Textur bereit:', gl.isTexture(tex));
Textur bereit: true

Textur im Shader verwenden und danach freigeben

// Annahme: program ist ein gelinktes WebGLProgram mit 'uniform sampler2D u_texture;'
const drawWithTexture = (gl, program, texture, vertexCount) => {
  gl.useProgram(program);
  gl.activeTexture(gl.TEXTURE0);          // Textureinheit 0 auswählen
  gl.bindTexture(gl.TEXTURE_2D, texture); // Textur an Einheit 0 binden
  const loc = gl.getUniformLocation(program, 'u_texture');
  gl.uniform1i(loc, 0);                   // Sampler zeigt auf Einheit 0
  gl.drawArrays(gl.TRIANGLES, 0, vertexCount);
};

// Aufräumen, z. B. beim Szenenwechsel
const disposeTexture = (gl, texture) => {
  gl.deleteTexture(texture);
  console.log(gl.isTexture(texture));
};
false

// Wichtig · Fallstricke

  • Kein Konstruktor: new WebGLTexture() wirft einen TypeError. Texturen erzeugst du nur über gl.createTexture().
  • Nur ein Kontext: Eine Textur gehört zu genau dem Kontext, der sie erzeugt hat. In einem anderen Canvas bzw. Kontext führt sie zu INVALID_OPERATION.
  • Unvollständige Texturen: Der Standardfilter TEXTURE_MIN_FILTER ist NEAREST_MIPMAP_LINEAR. Ohne Mipmaps wird die Textur deshalb schwarz gerendert, bis du generateMipmap() aufrufst oder den Filter auf LINEAR bzw. NEAREST stellst.
  • Nicht-Zweierpotenzen (NPOT): In WebGL 1 funktionieren NPOT-Texturen nur mit CLAMP_TO_EDGE und ohne Mipmaps. In WebGL 2 gilt diese Einschränkung nicht mehr.
  • CORS und Sicherheit: Bilder oder Videos von fremden Origins darfst du nur hochladen, wenn der Server CORS erlaubt und crossOrigin gesetzt ist. Sonst wirft texImage2D() einen SecurityError. So wird verhindert, dass Pixeldaten fremder Seiten ausgelesen werden.
  • Speicher: Der Garbage Collector gibt GPU-Speicher nicht zuverlässig frei. Ruf deshalb ausdrücklich gl.deleteTexture() auf. Geht der Kontext verloren (webglcontextlost), werden alle Texturen ungültig und müssen nach webglcontextrestored neu erzeugt werden.
  • Kompatibilität: Wird von allen modernen Browsern unterstützt, auch in Web Workers über OffscreenCanvas.