Signatur
Beschreibung
createBuffer() legt ein neues Buffer-Objekt auf der GPU an und gibt ein WebGLBuffer zurück, mit dem du auf dieses Objekt zugreifst. Der Buffer ist zunächst leer und hat noch keinen Typ. Erst mit gl.bindBuffer() wird er an ein Ziel gebunden, etwa gl.ARRAY_BUFFER für Vertex-Attribute oder gl.ELEMENT_ARRAY_BUFFER für Indizes. Danach überträgst du die Daten mit gl.bufferData().
Der typische Ablauf sieht so aus: anlegen → binden → befüllen → mit einem Attribut verknüpfen. Die Verknüpfung erledigen gl.vertexAttribPointer() und gl.enableVertexAttribArray(). Jede Geometrie, die du mit gl.drawArrays() oder gl.drawElements() zeichnest, braucht mindestens einen solchen Buffer.
Ein Buffer bleibt an das Ziel gebunden, an das er zuerst gebunden wurde. Ein ELEMENT_ARRAY_BUFFER lässt sich also später nicht als ARRAY_BUFFER verwenden. Brauchst du den Buffer nicht mehr, gibst du den GPU-Speicher mit gl.deleteBuffer() frei. So entstehen keine Speicherlecks, besonders bei Szenen, die sich häufig ändern.
Die Methode gibt es auch auf WebGL2RenderingContext. Dort kommen weitere Bindungsziele hinzu, zum Beispiel gl.UNIFORM_BUFFER, gl.COPY_READ_BUFFER und gl.TRANSFORM_FEEDBACK_BUFFER.
Rückgabewert
WebGLBuffer-Objekt. Ist der Kontext verloren gegangen (context lost), wird null zurückgegeben.Beispiele
Dreieck: Positions-Buffer anlegen und befüllen
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
// Drei Eckpunkte (x, y) in Clip-Koordinaten
const positions = new Float32Array([
0.0, 0.5,
-0.5, -0.5,
0.5, -0.5,
]);
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
console.log(positionBuffer instanceof WebGLBuffer);
console.log(gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE));
Buffer mit einem Shader-Attribut verknüpfen und zeichnen
// Annahme: 'program' ist ein gelinktes Shader-Programm
// mit dem Attribut 'a_position' (vec2)
const drawTriangle = (gl, program, buffer) => {
const loc = gl.getAttribLocation(program, 'a_position');
gl.useProgram(program);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(loc);
// 2 Komponenten pro Vertex, Float, nicht normalisiert, dicht gepackt
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 3);
};
drawTriangle(gl, program, positionBuffer);
Index-Buffer für ein Rechteck mit drawElements
const vertices = new Float32Array([
-0.5, 0.5, // 0 oben links
-0.5, -0.5, // 1 unten links
0.5, -0.5, // 2 unten rechts
0.5, 0.5, // 3 oben rechts
]);
const indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
const vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const ibo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
// ... Attribut wie oben einrichten, dann:
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
Aufräumen und Umgang mit Kontextverlust
const buffer = gl.createBuffer();
if (!buffer) {
console.warn('WebGL-Kontext verloren – Buffer konnte nicht erstellt werden.');
}
// Wenn der Buffer nicht mehr gebraucht wird:
gl.deleteBuffer(buffer);
console.log(gl.isBuffer(buffer));
canvas.addEventListener('webglcontextrestored', () => {
// Alle Buffer müssen neu erstellt und befüllt werden
initBuffers(gl);
});
// Wichtig · Fallstricke
- Kontextverlust: Verliert der Browser den Kontext (Event
webglcontextlost), werden alle Buffer ungültig undcreateBuffer()gibtnullzurück. Nachwebglcontextrestoredmusst du alle Buffer neu anlegen und befüllen. - Zielbindung ist endgültig: Ein Buffer, der einmal an
ELEMENT_ARRAY_BUFFERgebunden war, lässt sich nicht anARRAY_BUFFERbinden, und umgekehrt. Ein Versuch erzeugtINVALID_OPERATION. - Leerer Buffer:
createBuffer()reserviert noch keinen Datenspeicher. OhnebufferData()hat der Buffer die Größe 0, und Zeichenaufrufe schlagen fehl oder zeichnen nichts. - Performance: Lege Buffer möglichst einmal an und verwende sie wieder. Für Daten, die sich oft ändern, nimmst du
gl.DYNAMIC_DRAWzusammen mitbufferSubData(), statt in jedem Frame neue Buffer zu erzeugen. - Indextypen in WebGL 1:
Uint32Array-Indizes funktionieren nur mit der ErweiterungOES_element_index_uint. In WebGL 2 sind sie immer verfügbar. - Speicher freigeben: Gib nicht mehr benötigte Buffer mit
deleteBuffer()frei. Auf die Garbage Collection solltest du dich beim GPU-Speicher nicht verlassen. - Alle modernen Browser unterstützen die Methode, auch in
OffscreenCanvasund Web Workers.