Start · Sprachen · JavaScript · Referenz · WebGL2RenderingContext.drawRangeElements()

WebGL2RenderingContext.drawRangeElements()

Methode

Rendert indizierte Primitive aus dem gebundenen Element-Array-Buffer und gibt dabei zusätzlich an, in welchem Wertebereich <code>[start, end]</code> die verwendeten Indizes liegen.

seit JavaScript WebGL 2.0 – Baseline: alle modernen Browser (seit Kategorie: webapi

Signatur

WebGL2RenderingContext.prototype.drawRangeElements(mode, start, end, count, type, offset)

Beschreibung

drawRangeElements() funktioniert wie drawElements(): Die Methode liest count Indizes aus dem aktuell an ELEMENT_ARRAY_BUFFER gebundenen Buffer und zeichnet damit Primitive wie Dreiecke, Linien oder Punkte. Zusätzlich gibst du mit start und end an, welchen kleinsten und größten Indexwert die gelesenen Indizes haben.

Dieser Bereich ist ein Hinweis an die Implementierung. Der Treiber muss dann nur den Teil der Vertex-Attribute prüfen oder vorbereiten, der zwischen start und end liegt. Das ist besonders nützlich, wenn ein großer Vertex-Buffer mehrere Teil-Meshes enthält und du nur eines davon zeichnest.

Die Methode gibt es nur in einem WebGL-2-Kontext (canvas.getContext("webgl2")). In WebGL 1 gibt es sie nicht. Mit einem Vertex Array Object (VAO) wird der Element-Array-Buffer zusammen mit den Attribut-Einstellungen gespeichert. Deshalb reicht vor dem Aufruf meist ein bindVertexArray().

Parameter

Name Typ Default Beschreibung
$mode Pflicht GLenum Art der Primitive: gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN oder gl.TRIANGLES.
$start Pflicht GLuint Kleinster Indexwert, der in den gelesenen Indizes vorkommt.
$end Pflicht GLuint Größter Indexwert, der in den gelesenen Indizes vorkommt. Muss ≥ start sein.
$count Pflicht GLsizei Anzahl der Indizes, die gelesen und gezeichnet werden.
$type Pflicht GLenum Datentyp der Indizes: gl.UNSIGNED_BYTE, gl.UNSIGNED_SHORT oder gl.UNSIGNED_INT. UNSIGNED_INT steht in WebGL 2 ohne Erweiterung zur Verfügung.
$offset Pflicht GLintptr Byte-Offset im Element-Array-Buffer, an dem das Lesen beginnt. Er muss ein Vielfaches der Größe von type sein (z. B. 2 bei UNSIGNED_SHORT).

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Fehler werden über gl.getError() gemeldet.

Beispiele

Ein indiziertes Quadrat zeichnen

const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl2");

const vs = `#version 300 es
in vec2 aPos;
void main() { gl_Position = vec4(aPos, 0.0, 1.0); }`;
const fs = `#version 300 es
precision mediump float;
out vec4 color;
void main() { color = vec4(0.2, 0.6, 1.0, 1.0); }`;

const compile = (type, src) => {
  const s = gl.createShader(type);
  gl.shaderSource(s, src);
  gl.compileShader(s);
  return s;
};
const program = gl.createProgram();
gl.attachShader(program, compile(gl.VERTEX_SHADER, vs));
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, fs));
gl.linkProgram(program);
gl.useProgram(program);

const vao = gl.createVertexArray();
gl.bindVertexArray(vao);

// 4 Eckpunkte
const vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  -0.5, -0.5,  0.5, -0.5,  0.5, 0.5,  -0.5, 0.5
]), gl.STATIC_DRAW);
const loc = gl.getAttribLocation(program, "aPos");
gl.enableVertexAttribArray(loc);
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);

// 6 Indizes → 2 Dreiecke, Indexwerte liegen zwischen 0 und 3
const ibo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]), gl.STATIC_DRAW);

gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawRangeElements(gl.TRIANGLES, 0, 3, 6, gl.UNSIGNED_SHORT, 0);
console.log(gl.getError() === gl.NO_ERROR);
true

Teil-Mesh aus einem gemeinsamen Buffer zeichnen

// Annahme: VAO mit gemeinsamem Vertex- und Index-Buffer ist gebunden.
// Mesh A nutzt Vertices 0–99 und Indizes 0–299,
// Mesh B nutzt Vertices 100–179 und Indizes 300–539.
const meshes = [
  { start: 0,   end: 99,  count: 300, firstIndex: 0 },
  { start: 100, end: 179, count: 240, firstIndex: 300 }
];

const BYTES = Uint16Array.BYTES_PER_ELEMENT; // 2
for (const m of meshes) {
  gl.drawRangeElements(
    gl.TRIANGLES,
    m.start, m.end,        // Hinweis: nur dieser Vertex-Bereich wird benutzt
    m.count,
    gl.UNSIGNED_SHORT,
    m.firstIndex * BYTES   // Offset in Bytes, nicht in Indizes!
  );
}

Bereich automatisch aus den Indexdaten berechnen

const indices = new Uint32Array([10, 11, 12, 12, 13, 10]);
const start = Math.min(...indices);
const end = Math.max(...indices);

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);

// UNSIGNED_INT ist in WebGL 2 ohne Erweiterung erlaubt
gl.drawRangeElements(gl.TRIANGLES, start, end, indices.length, gl.UNSIGNED_INT, 0);
console.log(`Bereich: ${start}–${end}`);
Bereich: 10–13

// Wichtig · Fallstricke

  • Nur WebGL 2: In einem WebGL-1-Kontext ist drawRangeElements undefined. Unterstützt wird die Methode in allen aktuellen Browsern (Chrome, Firefox, Edge und Safari ab 15).
  • Offset in Bytes: offset ist eine Byte-Angabe, kein Index. Ist er kein Vielfaches der Typgröße, entsteht INVALID_OPERATION.
  • Bereich korrekt angeben: Liegen Indizes außerhalb von [start, end], ist das Ergebnis laut Spezifikation nicht definiert. WebGL führt zwar Bereichsprüfungen durch, um Speicherzugriffe außerhalb des Buffers zu verhindern, aber Rendering-Fehler sind trotzdem möglich. Ist end < start, entsteht INVALID_VALUE. Dasselbe gilt für ein negatives count.
  • Leistung: Der Nutzen hängt vom Treiber ab. Viele Implementierungen (z. B. ANGLE) behandeln die Methode fast genauso wie drawElements(). Ein messbarer Gewinn ist also nicht garantiert.
  • Ist kein ELEMENT_ARRAY_BUFFER gebunden, entsteht INVALID_OPERATION. Mit aktivem Transform Feedback ist das Zeichnen mit Indizes nicht erlaubt.
  • Ist Primitive-Restart aktiv, der in WebGL 2 immer eingeschaltet ist, gilt der Maximalwert des Index-Typs (z. B. 0xFFFF) als Neustart-Marke und nicht als echter Index.