Signatur
Beschreibung
multiDrawElementsWEBGL() gehört zur WebGL-Erweiterung WEBGL_multi_draw. Die Methode entspricht einer Schleife über gl.drawElements(mode, counts[i], type, offsets[i]), führt aber alle Zeichenvorgänge in einem API-Aufruf aus. Dadurch sinkt der CPU-Aufwand pro Draw-Call im JavaScript und im Browser-Treiber deutlich. Das lohnt sich vor allem bei vielen kleinen Meshes, die sich einen Vertex- und Index-Puffer teilen.
Für jeden Teil-Draw legst du fest, wie viele Indizes gelesen werden (countsList) und ab welchem Byte-Offset im gebundenen ELEMENT_ARRAY_BUFFER das Lesen beginnt (offsetsList). Mit den Parametern countsOffset und offsetsOffset kannst du einen Ausschnitt aus größeren Arrays verwenden, ohne neue Arrays anlegen zu müssen.
Im Vertex-Shader steht über #extension GL_ANGLE_multi_draw : require die eingebaute Variable gl_DrawID bereit. Sie enthält den Index des aktuellen Teil-Draws. Damit lassen sich pro Objekt eigene Daten wie Transformationen oder Farben aus Uniform-Arrays oder Texturen lesen – ohne die Uniforms zwischen den Draws zu ändern.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $mode Pflicht | GLenum | Primitivtyp: gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN oder gl.TRIANGLES. |
|
| $countsList Pflicht | Int32Array | Array<number> | Anzahl der Indizes, die pro Teil-Draw gelesen werden. | |
| $countsOffset Pflicht | number | Startposition (Element-Index, nicht Byte) in countsList. |
|
| $type Pflicht | GLenum | Datentyp der Indizes: gl.UNSIGNED_BYTE, gl.UNSIGNED_SHORT oder gl.UNSIGNED_INT. In WebGL 1 ist für gl.UNSIGNED_INT zusätzlich OES_element_index_uint nötig. |
|
| $offsetsList Pflicht | Int32Array | Array<number> | Byte-Offsets in den Element-Array-Puffer, ab denen pro Teil-Draw gelesen wird. Jeder Wert muss ein Vielfaches der Größe von type sein. |
|
| $offsetsOffset Pflicht | number | Startposition (Element-Index) in offsetsList. |
|
| $drawCount Pflicht | number | Anzahl der Teil-Draws, die ausgeführt werden. |
Rückgabewert
undefined). Fehler meldet die Methode wie üblich über gl.getError().Beispiele
Drei Meshes aus einem gemeinsamen Index-Puffer zeichnen
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2');
const ext = gl.getExtension('WEBGL_multi_draw');
if (!ext) throw new Error('WEBGL_multi_draw wird nicht unterstützt');
// Annahme: Programm, VAO und Vertex-Attribute sind bereits eingerichtet.
// Ein gemeinsamer Index-Puffer für drei Objekte (Uint16 = 2 Byte pro Index)
const indices = new Uint16Array([
0, 1, 2, // Objekt A: 3 Indizes
3, 4, 5, 5, 4, 6, // Objekt B: 6 Indizes
7, 8, 9 // Objekt C: 3 Indizes
]);
const ibo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
const counts = new Int32Array([3, 6, 3]);
const offsets = new Int32Array([0, 3 * 2, 9 * 2]); // Byte-Offsets!
ext.multiDrawElementsWEBGL(
gl.TRIANGLES,
counts, 0,
gl.UNSIGNED_SHORT,
offsets, 0,
counts.length
);
console.log(gl.getError() === gl.NO_ERROR);
Objekt-Farbe pro Draw über gl_DrawID (WebGL 2 / GLSL ES 3.00)
const vsSource = `#version 300 es
#extension GL_ANGLE_multi_draw : require
in vec2 aPos;
uniform vec2 uOffsets[3];
flat out int vId;
void main() {
vId = gl_DrawID;
gl_Position = vec4(aPos + uOffsets[gl_DrawID], 0.0, 1.0);
}`;
const fsSource = `#version 300 es
precision mediump float;
flat in int vId;
uniform vec3 uColors[3];
out vec4 outColor;
void main() { outColor = vec4(uColors[vId], 1.0); }`;
// Nach dem Kompilieren und Linken (program):
gl.useProgram(program);
gl.uniform2fv(gl.getUniformLocation(program, 'uOffsets'), [-0.5, 0, 0, 0, 0.5, 0]);
gl.uniform3fv(gl.getUniformLocation(program, 'uColors'), [1, 0, 0, 0, 1, 0, 0, 0, 1]);
ext.multiDrawElementsWEBGL(gl.TRIANGLES, [3, 3, 3], 0, gl.UNSIGNED_SHORT, [0, 6, 12], 0, 3);
Ausschnitt aus großen Arrays zeichnen (Culling-Ergebnis)
// Vorab berechnete Listen für 1000 Objekte
const allCounts = new Int32Array(1000).fill(36);
const allOffsets = Int32Array.from({ length: 1000 }, (_, i) => i * 36 * 2);
// Nur Objekte 200 bis 299 sind sichtbar
const first = 200;
const visible = 100;
ext.multiDrawElementsWEBGL(
gl.TRIANGLES,
allCounts, first,
gl.UNSIGNED_SHORT,
allOffsets, first,
visible
);