Signatur
Beschreibung
vertexAttribPointer() sagt der GPU, wie sie die Rohdaten eines Vertex-Puffers lesen soll: wie viele Komponenten zu einem Attribut gehören (z. B. 3 bei einer Position vec3), welchen Datentyp sie haben, ob sie normalisiert werden, wie viele Bytes zwischen zwei aufeinanderfolgenden Vertices liegen (stride) und ab welchem Byte das Attribut beginnt (offset).
Der Aufruf bezieht sich immer auf den Puffer, der zum Zeitpunkt des Aufrufs an gl.ARRAY_BUFFER gebunden ist. Diese Verknüpfung wird im Attribut-Zustand gespeichert. Danach kannst du einen anderen Puffer binden, ohne dass sich die Zuordnung ändert. So lassen sich mehrere Attribute aus verschiedenen Puffern speisen, oder aus einem einzigen verschachtelten Puffer (interleaved), bei dem Position, Farbe und Texturkoordinaten direkt hintereinander liegen.
Damit das Attribut beim Zeichnen wirklich aus dem Puffer gelesen wird, musst du es zusätzlich mit gl.enableVertexAttribArray(index) aktivieren. Den index bekommst du normalerweise über gl.getAttribLocation(program, "aName"). In WebGL 2 (oder mit der Erweiterung OES_vertex_array_object) wird dieser ganze Zustand in einem Vertex Array Object (VAO) gespeichert. Das spart beim Zeichnen viele Aufrufe.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $index Pflicht | GLuint (number) | Index des Vertex-Attributs, meist aus gl.getAttribLocation(). Muss kleiner als gl.getParameter(gl.MAX_VERTEX_ATTRIBS) sein. |
|
| $size Pflicht | GLint (1 | 2 | 3 | 4) | Anzahl der Komponenten pro Vertex-Attribut, z. B. 2 für vec2 und 3 für vec3. |
|
| $type Pflicht | GLenum | Datentyp jeder Komponente: gl.FLOAT, gl.BYTE, gl.UNSIGNED_BYTE, gl.SHORT oder gl.UNSIGNED_SHORT. WebGL 2 erlaubt zusätzlich gl.HALF_FLOAT, gl.INT, gl.UNSIGNED_INT und gl.INT_2_10_10_10_REV. |
|
| $normalized Pflicht | GLboolean (boolean) | Nur für Ganzzahltypen relevant. Bei true werden die Werte auf [0, 1] (vorzeichenlos) bzw. [-1, 1] (vorzeichenbehaftet) abgebildet, z. B. 255 → 1.0 bei UNSIGNED_BYTE. Bei gl.FLOAT hat der Wert keine Wirkung. |
|
| $stride Pflicht | GLsizei (number) | Abstand in Bytes zwischen dem Anfang zweier aufeinanderfolgender Vertices (0–255). 0 bedeutet: dicht gepackt, die Schrittweite ergibt sich dann aus size × Typgröße. |
|
| $offset Pflicht | GLintptr (number) | Byte-Offset des ersten Elements im Puffer. Muss ein Vielfaches der Byte-Größe von type sein. |
Rückgabewert
gl.getError() abfragen.Beispiele
Dicht gepackte Positionsdaten für ein Dreieck
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const vsSource = `
attribute vec2 aPosition;
void main() { gl_Position = vec4(aPosition, 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 s = gl.createShader(type);
gl.shaderSource(s, src);
gl.compileShader(s);
return s;
};
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);
const positions = new Float32Array([0, 0.5, -0.5, -0.5, 0.5, -0.5]);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
const loc = gl.getAttribLocation(program, 'aPosition');
// 2 Floats pro Vertex, dicht gepackt (stride 0), ab Byte 0
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(loc);
gl.drawArrays(gl.TRIANGLES, 0, 3);
Verschachtelter Puffer: Position und Farbe
// Layout pro Vertex: x, y, r, g, b (5 Floats = 20 Bytes)
const data = new Float32Array([
0.0, 0.5, 1, 0, 0,
-0.5, -0.5, 0, 1, 0,
0.5, -0.5, 0, 0, 1,
]);
const FSIZE = Float32Array.BYTES_PER_ELEMENT; // 4
const stride = 5 * FSIZE;
const vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
const posLoc = gl.getAttribLocation(program, 'aPosition');
const colLoc = gl.getAttribLocation(program, 'aColor');
gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, stride, 0);
gl.enableVertexAttribArray(posLoc);
// Farbe beginnt nach 2 Floats = 8 Bytes
gl.vertexAttribPointer(colLoc, 3, gl.FLOAT, false, stride, 2 * FSIZE);
gl.enableVertexAttribArray(colLoc);
gl.drawArrays(gl.TRIANGLES, 0, 3);
Kompakte Farben als normalisierte Bytes
// RGBA als Uint8 (0–255) spart 75 % Speicher gegenüber Float32
const colors = new Uint8Array([
255, 0, 0, 255,
0, 255, 0, 255,
0, 0, 255, 255,
]);
const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
const colLoc = gl.getAttribLocation(program, 'aColor'); // vec4 im Shader
// normalized = true: 255 wird im Shader zu 1.0
gl.vertexAttribPointer(colLoc, 4, gl.UNSIGNED_BYTE, true, 0, 0);
gl.enableVertexAttribArray(colLoc);