Signatur
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 übergl_PointSizeim Vertex-Shader)gl.LINES,gl.LINE_STRIP,gl.LINE_LOOP: einzelne Linien, ein offener Linienzug oder ein geschlossener Linienzuggl.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
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);
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
countzählt Vertices, keine Floats: Bei einemvec2-Attribut mit 6 Floats istcountgleich 3. Ist der Wert zu groß, liest WebGL über das Pufferende hinaus und meldetINVALID_OPERATION, statt zu zeichnen.- Fehlercodes:
INVALID_ENUMbei ungültigemmode,INVALID_VALUEbei negativemfirstodercount,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 Entwicklunggl.getError()prüfen. - Nichts zu sehen? Häufige Ursachen: vergessenes
enableVertexAttribArray(), falschevertexAttribPointer()-Parameter, Koordinaten außerhalb des Clip-Space (−1 bis 1), Face Culling bei falscher Umlaufrichtung, odergl_PointSizefehlt beigl.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 ErweiterungANGLE_instanced_arraysin 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
WebGL2RenderingContextundOffscreenCanvas. Nach einem Kontextverlust (webglcontextlost) haben Aufrufe keine Wirkung.