Start · Sprachen · JavaScript · Referenz · WebGLRenderingContext.drawArrays()

WebGLRenderingContext.drawArrays()

Methode

Rendert geometrische Primitive (Punkte, Linien, Dreiecke) direkt aus den aktivierten Vertex-Attribut-Arrays, ohne Index-Puffer.

seit JavaScript WebGL 1.0 – Baseline: alle modernen Browser Kategorie: webapi

Signatur

WebGLRenderingContext.prototype.drawArrays(mode, first, count)

Beschreibung

drawArrays() ist der einfachste Zeichenaufruf in WebGL. Die Methode liest count Vertices ab Position first aus den aktuell gebundenen und per enableVertexAttribArray() aktivierten Vertex-Attributen und setzt sie gemäß mode zu Primitiven zusammen. Dafür wird das aktuell mit useProgram() gesetzte Shader-Programm verwendet.

Anders als drawElements() braucht drawArrays() keinen Index-Puffer (ELEMENT_ARRAY_BUFFER). Jeder Vertex wird in der Reihenfolge verarbeitet, in der er im Puffer steht. Das eignet sich für einfache Geometrie, Partikelsysteme (gl.POINTS), Linienzüge oder Vollbild-Quads für Post-Processing. Bei Meshes, deren Vertices mehrfach genutzt werden, ist drawElements() meist speichersparender.

Diese Primitiv-Modi gibt es:

  • gl.POINTS: ein Punkt je Vertex (Größe über gl_PointSize im Vertex-Shader)
  • gl.LINES, gl.LINE_STRIP, gl.LINE_LOOP: einzelne Linien, ein offener Linienzug oder ein geschlossener Linienzug
  • gl.TRIANGLES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN: einzelne Dreiecke, ein Streifen oder ein Fächer

Vor dem Aufruf müssen ein gültiges Programm, gebundene Puffer mit ausreichend Daten und alle nötigen Uniforms gesetzt sein. Gezeichnet wird in den aktuell gebundenen Framebuffer, standardmäßig also in das Canvas.

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.
$first Pflicht GLint (number) Index des ersten Vertex, der gelesen wird. Muss ≥ 0 sein.
$count Pflicht GLsizei (number) Anzahl der zu zeichnenden Vertices (nicht die Anzahl der Primitive und nicht die Anzahl der Float-Werte). Muss ≥ 0 sein.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Fehler meldet die Methode über gl.getError().

Beispiele

Ein farbiges Dreieck zeichnen

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');

const vsSource = `
  attribute vec2 aPos;
  void main() { gl_Position = vec4(aPos, 0.0, 1.0); }
`;
const fsSource = `
  precision mediump float;
  void main() { gl_FragColor = vec4(1.0, 0.4, 0.1, 1.0); }
`;

const compile = (type, src) => {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, src);
  gl.compileShader(shader);
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    throw new Error(gl.getShaderInfoLog(shader));
  }
  return shader;
};

const program = gl.createProgram();
gl.attachShader(program, compile(gl.VERTEX_SHADER, vsSource));
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(program);
gl.useProgram(program);

// 3 Vertices mit je 2 Komponenten (x, y)
const vertices = new Float32Array([0, 0.8, -0.8, -0.8, 0.8, -0.8]);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

const aPos = gl.getAttribLocation(program, 'aPos');
gl.enableVertexAttribArray(aPos);
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);

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

Vollbild-Quad mit TRIANGLE_STRIP (Post-Processing)

// Vorausgesetzt: gl, program und das Attribut aPos sind wie oben eingerichtet
const quad = new Float32Array([
  -1, -1,
   1, -1,
  -1,  1,
   1,  1
]);
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW);
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);

// 4 Vertices ergeben 2 Dreiecke, die den ganzen Viewport abdecken
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

Teilbereich eines Puffers als Punkte und Linienzug zeichnen

// Puffer enthält 100 Messpunkte (x, y) eines Diagramms
const points = new Float32Array(200);
for (let i = 0; i < 100; i++) {
  points[i * 2] = (i / 99) * 2 - 1;
  points[i * 2 + 1] = Math.sin(i / 10) * 0.8;
}
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);

// Nur die Punkte 20 bis 69 zeichnen
gl.drawArrays(gl.LINE_STRIP, 20, 50);
// Dieselben Daten zusätzlich als Punkte (Vertex-Shader setzt gl_PointSize)
gl.drawArrays(gl.POINTS, 20, 50);

// Wichtig · Fallstricke

  • count zählt Vertices, keine Floats: Bei einem vec2-Attribut mit 6 Floats ist count gleich 3. Ist der Wert zu groß, liest WebGL über das Pufferende hinaus und meldet INVALID_OPERATION, statt zu zeichnen.
  • Fehlercodes: INVALID_ENUM bei ungültigem mode, INVALID_VALUE bei negativem first oder count, INVALID_OPERATION, wenn kein Programm aktiv ist oder ein aktiviertes Attribut auf keinen bzw. einen zu kleinen Puffer zeigt. Der Aufruf wirft keine Exception, deshalb während der Entwicklung gl.getError() prüfen.
  • Nichts zu sehen? Häufige Ursachen: vergessenes enableVertexAttribArray(), falsche vertexAttribPointer()-Parameter, Koordinaten außerhalb des Clip-Space (−1 bis 1), Face Culling bei falscher Umlaufrichtung, oder gl_PointSize fehlt bei gl.POINTS.
  • Performance: Jeder Zeichenaufruf kostet CPU-Zeit. Viele kleine Aufrufe möglichst zu einem Puffer bündeln (Batching) oder Instancing nutzen: drawArraysInstanced() in WebGL 2 bzw. die Erweiterung ANGLE_instanced_arrays in WebGL 1.
  • Linienbreite: gl.lineWidth() wird von den meisten Implementierungen ignoriert (maximal 1 px). Für dicke Linien muss man Dreiecke erzeugen.
  • Kompatibilität: Die Methode wird in allen modernen Browsern unterstützt, auch in WebGL2RenderingContext und OffscreenCanvas. Nach einem Kontextverlust (webglcontextlost) haben Aufrufe keine Wirkung.