Start · Sprachen · JavaScript · Referenz · WEBGL_multi_draw.multiDrawElementsWEBGL()

WEBGL_multi_draw.multiDrawElementsWEBGL()

Methode

Rendert mit einem einzigen Aufruf mehrere indizierte Primitiven-Gruppen aus dem gebundenen Element-Array-Puffer – wie mehrere <code>drawElements()</code>-Aufrufe hintereinander.

seit JavaScript WebGL-Erweiterung (WebGL 1 und WebGL 2); Chromium- Kategorie: webapi

Signatur

WEBGL_multi_draw.multiDrawElementsWEBGL(mode, countsList, countsOffset, type, offsetsList, offsetsOffset, drawCount)

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

Typ
void
Beschreibung
Kein 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);
true

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
);