Signatur
Beschreibung
bufferSubData() schreibt neue Daten in einen bereits angelegten Pufferspeicher. Anders als bufferData() wird dabei kein neuer Speicher auf der GPU reserviert – die Größe des Puffers bleibt unverändert, es werden nur die Bytes ab offset ersetzt.
Typische Einsatzfälle sind dynamische Geometrie: Partikelsysteme, animierte Vertex-Positionen, Text- oder UI-Batches, bei denen sich pro Frame nur ein Teil der Daten ändert. Man legt den Puffer einmalig mit bufferData(target, size, gl.DYNAMIC_DRAW) in ausreichender Größe an und aktualisiert ihn danach mit bufferSubData(). Das vermeidet teure Neuallokationen.
Die Methode wirkt immer auf den Puffer, der aktuell an target gebunden ist – vorher muss also gl.bindBuffer() aufgerufen werden. In WebGL 2 (WebGL2RenderingContext) gibt es eine erweiterte Überladung bufferSubData(target, dstByteOffset, srcData, srcOffset, length), mit der nur ein Ausschnitt eines Typed Arrays übertragen werden kann, ohne eine subarray()-Kopie zu erzeugen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $target Pflicht | GLenum | Bindungspunkt des Puffers: gl.ARRAY_BUFFER (Vertex-Attribute) oder gl.ELEMENT_ARRAY_BUFFER (Indizes). In WebGL 2 zusätzlich u. a. gl.UNIFORM_BUFFER, gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, gl.TRANSFORM_FEEDBACK_BUFFER, gl.PIXEL_PACK_BUFFER, gl.PIXEL_UNPACK_BUFFER. |
|
| $offset Pflicht | GLintptr (number) | Startposition im Puffer in Bytes, ab der geschrieben wird. Nicht die Element-Anzahl! | |
| $srcData Pflicht | ArrayBuffer | SharedArrayBuffer | ArrayBufferView | Die zu kopierenden Daten, meist ein Typed Array wie Float32Array oder Uint16Array. |
|
| $srcOffset | GLuint (number) | 0 | Nur WebGL 2, nur bei ArrayBufferView: Startindex in Elementen innerhalb von srcData. |
| $length | GLuint (number) | 0 | Nur WebGL 2: Anzahl der zu kopierenden Elemente. 0 bedeutet: bis zum Ende von srcData. |
Rückgabewert
undefined). Fehler werden über gl.getError() gemeldet.Beispiele
Puffer einmal anlegen, dann Teil aktualisieren
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
// Platz für 3 Vertices × 2 Floats reservieren (24 Bytes)
gl.bufferData(gl.ARRAY_BUFFER, 6 * Float32Array.BYTES_PER_ELEMENT, gl.DYNAMIC_DRAW);
// Nur den zweiten Vertex (Floats 2 und 3) überschreiben
const secondVertex = new Float32Array([0.5, -0.5]);
gl.bufferSubData(gl.ARRAY_BUFFER, 2 * Float32Array.BYTES_PER_ELEMENT, secondVertex);
console.log(gl.getError() === gl.NO_ERROR);
Partikelpositionen pro Frame aktualisieren
const gl = document.querySelector('canvas').getContext('webgl');
const MAX_PARTICLES = 1000;
const positions = new Float32Array(MAX_PARTICLES * 2);
const posBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positions.byteLength, gl.DYNAMIC_DRAW);
const frame = (time) => {
for (let i = 0; i < MAX_PARTICLES; i++) {
positions[i * 2] = Math.sin(time * 0.001 + i) * 0.9;
positions[i * 2 + 1] = Math.cos(time * 0.0013 + i) * 0.9;
}
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
// Gesamten Inhalt ersetzen, ohne neu zu allozieren
gl.bufferSubData(gl.ARRAY_BUFFER, 0, positions);
gl.drawArrays(gl.POINTS, 0, MAX_PARTICLES);
requestAnimationFrame(frame);
};
requestAnimationFrame(frame);
WebGL 2: Ausschnitt eines Typed Arrays ohne Kopie hochladen
const gl = document.createElement('canvas').getContext('webgl2');
const data = new Float32Array([0, 1, 2, 3, 4, 5, 6, 7]);
const buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, data.byteLength, gl.DYNAMIC_DRAW);
// Elemente 4..7 aus data an Byte-Offset 0 im Puffer schreiben
gl.bufferSubData(gl.ARRAY_BUFFER, 0, data, 4, 4);
// Zurücklesen (nur WebGL 2)
const result = new Float32Array(8);
gl.getBufferSubData(gl.ARRAY_BUFFER, 0, result);
console.log(Array.from(result));
// Wichtig · Fallstricke
- Offset in Bytes:
offsetzählt Bytes, nicht Elemente. BeiFloat32Arrayalso mit4(BYTES_PER_ELEMENT) multiplizieren. In WebGL 2 zählensrcOffset/lengthdagegen in Elementen – eine häufige Verwechslung. - Kein Vergrößern: Wenn
offset + srcData.byteLengthdie mitbufferData()festgelegte Größe überschreitet, entstehtgl.INVALID_VALUEund nichts wird geschrieben. Ein negativer Offset erzeugt ebenfallsINVALID_VALUE. - Ist an
targetkein Puffer gebunden (null), wirdgl.INVALID_OPERATIONgemeldet; ein ungültigestargetergibtgl.INVALID_ENUM. - Performance: Häufige kleine Aufrufe sind teuer – Änderungen besser in einem Typed Array sammeln und in einem Aufruf hochladen. Der Puffer sollte mit
DYNAMIC_DRAWbzw.STREAM_DRAWangelegt werden. Bei Pro-Frame-Updates kann „Buffer Orphaning“ (erneutesbufferData()mit gleicher Größe) oder Doppelpufferung Stalls vermeiden, wenn die GPU den Puffer noch liest. ELEMENT_ARRAY_BUFFER: In WebGL gilt die Bindung pro Vertex Array Object; ein Index-Puffer darf zudem nicht gleichzeitig alsARRAY_BUFFERverwendet werden.- Kompatibilität: WebGL 1 wird von allen modernen Browsern unterstützt; die Überladung mit
srcOffset/lengthnur in WebGL-2-Kontexten (ebenfalls breit verfügbar, Safari ab 15).