Signatur
Beschreibung
In WebGL bekommt der Vertex-Shader seine Daten (Positionen, Normalen, Texturkoordinaten, Farben …) über Attribute. Jedes Attribut hat einen numerischen Index (Location). Standardmäßig sind alle Attribut-Arrays deaktiviert. Dann liefert das Attribut bei jedem Vertex denselben konstanten Wert, den man mit vertexAttrib[1234]f[v]() setzt. Erst enableVertexAttribArray(index) sorgt dafür, dass drawArrays() und drawElements() für jeden Vertex eigene Werte aus dem Puffer lesen, der mit vertexAttribPointer() beschrieben wurde.
Der übliche Ablauf sieht so aus: Mit getAttribLocation() den Index ermitteln, den Puffer mit bindBuffer(gl.ARRAY_BUFFER, …) binden, das Datenlayout mit vertexAttribPointer() festlegen und das Array mit enableVertexAttribArray() aktivieren. Die Reihenfolge von vertexAttribPointer() und enableVertexAttribArray() spielt keine Rolle. Wichtig ist nur, dass vor dem Zeichenaufruf beides erledigt ist.
Der Aktivierungszustand ist globaler Zustand des Kontexts (bei WebGL 2 bzw. mit der Erweiterung OES_vertex_array_object gehört er zum aktuell gebundenen Vertex Array Object). Mit disableVertexAttribArray() schaltet man ein Attribut wieder ab, zum Beispiel wenn ein anderes Shader-Programm dieses Attribut nicht nutzt.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $index Pflicht | GLuint (number) | Index (Location) des Vertex-Attributs, das aktiviert werden soll. Man erhält ihn meist über gl.getAttribLocation(program, name). Er muss kleiner sein als gl.getParameter(gl.MAX_VERTEX_ATTRIBS). |
Rückgabewert
undefined). Fehler meldet die Methode über gl.getError().Beispiele
Positionsattribut für ein Dreieck aktivieren
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.5, 0.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, vsSource));
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, fsSource));
gl.linkProgram(program);
gl.useProgram(program);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0.8, -0.8, -0.8, 0.8, -0.8]), gl.STATIC_DRAW);
const loc = gl.getAttribLocation(program, 'aPosition');
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(loc); // ohne diese Zeile: alle Vertices = (0,0,0,1)
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
Verschachtelte Daten: Position und Farbe aus einem Puffer
// Layout pro Vertex: x, y, r, g, b (5 Floats = 20 Bytes)
const data = new Float32Array([
0.0, 0.8, 1, 0, 0,
-0.8, -0.8, 0, 1, 0,
0.8, -0.8, 0, 0, 1,
]);
const FSIZE = data.BYTES_PER_ELEMENT;
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
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, 5 * FSIZE, 0);
gl.vertexAttribPointer(colLoc, 3, gl.FLOAT, false, 5 * FSIZE, 2 * FSIZE);
// Beide Attribut-Arrays aktivieren
[posLoc, colLoc].forEach((loc) => gl.enableVertexAttribArray(loc));
gl.drawArrays(gl.TRIANGLES, 0, 3);
Location prüfen und Fehler abfragen
const loc = gl.getAttribLocation(program, 'aNormal');
if (loc === -1) {
// Attribut existiert nicht oder wurde vom Compiler wegoptimiert
console.warn('aNormal nicht gefunden – Aktivierung übersprungen');
} else {
gl.enableVertexAttribArray(loc);
}
console.log('Max. Attribute:', gl.getParameter(gl.MAX_VERTEX_ATTRIBS));
gl.enableVertexAttribArray(9999);
console.log(gl.getError() === gl.INVALID_VALUE);
// Wichtig · Fallstricke
- Location -1:
getAttribLocation()gibt-1zurück, wenn das Attribut nicht existiert oder im Shader nicht benutzt und deshalb wegoptimiert wurde.enableVertexAttribArray(-1)wird zu einem sehr großenGLuintumgewandelt und löstINVALID_VALUEaus. Deshalb die Location vorher immer prüfen. - Index zu groß: Ist
index >= MAX_VERTEX_ATTRIBS(garantiert sind mindestens 8, üblich sind 16), setzt WebGL den Fehlergl.INVALID_VALUE. Eine Ausnahme wird dabei nicht geworfen. - Aktiviert, aber kein Puffer gebunden: Ist ein Attribut-Array aktiviert, ohne dass über
vertexAttribPointer()ein Puffer zugeordnet wurde, oder reicht der Puffer nicht für alle gezeichneten Vertices, dann lösendrawArrays()unddrawElements()INVALID_OPERATIONaus und es wird nichts gezeichnet. - Zustand bleibt bestehen: Die Aktivierung gilt für den ganzen Kontext bzw. für das gebundene VAO und nicht für das Shader-Programm. Beim Wechsel zwischen Programmen mit unterschiedlichen Attributen sollte man nicht benötigte Arrays mit
disableVertexAttribArray()abschalten. Alternativ nutzt man Vertex Array Objects (WebGL 2:createVertexArray(), WebGL 1: ErweiterungOES_vertex_array_object). - Attribut 0: Manche Desktop-OpenGL-Treiber arbeiten langsamer, wenn das Attribut 0 nicht als Array aktiviert ist. Mit
bindAttribLocation(program, 0, 'aPosition')vor dem Linken lässt sich ein immer genutztes Attribut auf Index 0 legen. - Die Methode gibt es genauso auch in
WebGL2RenderingContext. Alle modernen Browser unterstützen sie.