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

WebGLRenderingContext.texSubImage2D()

Methode

Überschreibt ein rechteckiges Teilstück einer bereits angelegten 2D-Textur mit neuen Pixeldaten, ohne den Speicher der Textur neu zu reservieren.

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

Signatur

WebGLRenderingContext.prototype.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels) | texSubImage2D(target, level, xoffset, yoffset, format, type, source)

Beschreibung

texSubImage2D() ersetzt einen rechteckigen Bereich eines Texturbildes, das vorher mit texImage2D() angelegt wurde. Der Speicher der Textur wird dabei nicht neu reserviert, nur die Texel im angegebenen Bereich werden ersetzt. Deshalb ist die Methode deutlich schneller als ein erneuter Aufruf von texImage2D(), wenn sich Größe und Format nicht ändern.

Typische Einsatzfälle sind Videotexturen, die in jedem Frame aktualisiert werden, Texturatlanten, in die Glyphen oder Sprites nachträglich eingefügt werden, dynamische Heightmaps und Datentexturen für GPGPU-Berechnungen oder Partikelsysteme.

Es gibt zwei Formen des Aufrufs:

  • Mit rohen Pixeldaten: Du übergibst width, height und ein ArrayBufferView, zum Beispiel ein Uint8Array.
  • Mit einer DOM- oder Bildquelle, etwa HTMLImageElement, HTMLCanvasElement, HTMLVideoElement, ImageBitmap, ImageData oder OffscreenCanvas. Breite und Höhe werden dann aus der Quelle übernommen.

Die Textur muss vorher mit bindTexture() an das passende Ziel gebunden sein. format und type müssen zum internen Format passen, das beim ursprünglichen texImage2D() gewählt wurde.

Parameter

Name Typ Default Beschreibung
$target Pflicht GLenum Das Bindungsziel: gl.TEXTURE_2D oder eine Würfelseite wie gl.TEXTURE_CUBE_MAP_POSITIVE_X (entsprechend auch NEGATIVE_X, POSITIVE_Y usw.).
$level Pflicht GLint Die Mipmap-Stufe, die aktualisiert wird. 0 ist das Basisbild.
$xoffset Pflicht GLint Horizontaler Versatz des Teilrechtecks innerhalb der Textur, in Texeln.
$yoffset Pflicht GLint Vertikaler Versatz des Teilrechtecks innerhalb der Textur, in Texeln.
$width GLsizei Breite des Teilrechtecks. Gibt es nur in der Form mit ArrayBufferView.
$height GLsizei Höhe des Teilrechtecks. Gibt es nur in der Form mit ArrayBufferView.
$format Pflicht GLenum Das Format der Quelldaten, z. B. gl.RGBA, gl.RGB, gl.ALPHA, gl.LUMINANCE oder gl.LUMINANCE_ALPHA. Muss zum Format der Textur passen.
$type Pflicht GLenum Der Datentyp der Texel, z. B. gl.UNSIGNED_BYTE, gl.UNSIGNED_SHORT_5_6_5, gl.UNSIGNED_SHORT_4_4_4_4 oder gl.FLOAT (braucht die Erweiterung OES_texture_float).
$pixels ArrayBufferView | null Die rohen Pixeldaten. Der typisierte Array-Typ muss zu type passen, etwa Uint8Array für UNSIGNED_BYTE oder Uint16Array für UNSIGNED_SHORT_5_6_5.
$source ImageBitmap | ImageData | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | OffscreenCanvas | VideoFrame Eine Bild- oder Videoquelle. Wird statt width, height und pixels übergeben.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Fehler meldet WebGL über gl.getError().

Beispiele

Einzelnes Texel in einer Datentextur ändern

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

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

// 4×4-Textur anlegen, komplett schwarz
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 4, 4, 0,
  gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4 * 4 * 4));

// Texel an Position (2, 1) auf Rot setzen
const red = new Uint8Array([255, 0, 0, 255]);
gl.texSubImage2D(gl.TEXTURE_2D, 0, 2, 1, 1, 1,
  gl.RGBA, gl.UNSIGNED_BYTE, red);

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

Videotextur in jedem Frame aktualisieren

const gl = document.querySelector('#view').getContext('webgl');
const video = document.querySelector('video');

const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
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);

video.addEventListener('loadeddata', () => {
  // Speicher einmalig in Videogröße anlegen
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);

  const render = () => {
    gl.bindTexture(gl.TEXTURE_2D, tex);
    // Nur Inhalt ersetzen, kein neuer Speicher
    gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, video);
    // ... zeichnen ...
    requestAnimationFrame(render);
  };
  requestAnimationFrame(render);
});

Bild in einen Texturatlas einfügen

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

const atlas = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, atlas);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1024, 1024, 0,
  gl.RGBA, gl.UNSIGNED_BYTE, null); // leerer Speicher
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

const addToAtlas = async (url, x, y) => {
  const blob = await (await fetch(url)).blob();
  const bitmap = await createImageBitmap(blob);
  gl.bindTexture(gl.TEXTURE_2D, atlas);
  gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, gl.RGBA, gl.UNSIGNED_BYTE, bitmap);
  bitmap.close();
  return { x, y, w: bitmap.width, h: bitmap.height };
};

const slot = await addToAtlas('/sprites/held.png', 128, 0);
console.log(slot);
{ x: 128, y: 0, w: 64, h: 64 }