Signatur
Beschreibung
Die Methode createVertexArrayOES() der WebGL-1-Erweiterung OES_vertex_array_object legt ein neues, leeres Vertex-Array-Objekt (VAO) an. Ein VAO speichert alle Einstellungen, die mit vertexAttribPointer(), enableVertexAttribArray() und dem gebundenen ELEMENT_ARRAY_BUFFER gemacht werden. Danach kann man diesen Zustand mit einem einzigen Aufruf von bindVertexArrayOES() wiederherstellen.
Das lohnt sich vor allem, wenn eine Szene viele verschiedene Meshes enthält. Ohne VAO musst du vor jedem Draw-Call alle Attribut-Zeiger neu setzen. Mit VAO bindest du pro Mesh nur ein Objekt. Das macht den Code übersichtlicher und spart CPU-Zeit im Treiber.
Die Erweiterung holst du mit gl.getExtension("OES_vertex_array_object"). In WebGL 2 gehören VAOs zum Kern der API. Dort heißt die Methode gl.createVertexArray() und du brauchst keine Erweiterung.
Das erzeugte Objekt ist zuerst nur ein Name ohne Zustand. Es wird erst dann gültig und befüllt, wenn du es mit bindVertexArrayOES() bindest und danach Attribute konfigurierst.
Rückgabewert
WebGLVertexArrayObject. Ist der WebGL-Kontext verloren gegangen, kommt null zurück.Beispiele
Erweiterung abfragen und VAO erstellen
const canvas = document.createElement("canvas");
const gl = canvas.getContext("webgl");
const ext = gl.getExtension("OES_vertex_array_object");
if (!ext) {
throw new Error("OES_vertex_array_object wird nicht unterstützt");
}
const vao = ext.createVertexArrayOES();
console.log(vao instanceof WebGLVertexArrayObjectOES);
console.log(ext.isVertexArrayOES(vao)); // noch nicht gebunden
Attribut-Zustand in einem VAO speichern und zum Zeichnen nutzen
const gl = document.querySelector("canvas").getContext("webgl");
const ext = gl.getExtension("OES_vertex_array_object");
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.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);
// VAO anlegen und binden – alles Folgende wird darin gespeichert
const triangleVAO = ext.createVertexArrayOES();
ext.bindVertexArrayOES(triangleVAO);
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, "aPos");
gl.enableVertexAttribArray(loc);
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
ext.bindVertexArrayOES(null); // Zustand "einfrieren"
// Im Render-Loop reicht ein einziger Bind-Aufruf
const render = () => {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(program);
ext.bindVertexArrayOES(triangleVAO);
gl.drawArrays(gl.TRIANGLES, 0, 3);
ext.bindVertexArrayOES(null);
};
render();
Fallback-Helfer für WebGL 1 und WebGL 2
const createVAOApi = (gl) => {
if (typeof WebGL2RenderingContext !== "undefined" && gl instanceof WebGL2RenderingContext) {
return {
create: () => gl.createVertexArray(),
bind: (vao) => gl.bindVertexArray(vao),
remove: (vao) => gl.deleteVertexArray(vao),
};
}
const ext = gl.getExtension("OES_vertex_array_object");
if (!ext) return null;
return {
create: () => ext.createVertexArrayOES(),
bind: (vao) => ext.bindVertexArrayOES(vao),
remove: (vao) => ext.deleteVertexArrayOES(vao),
};
};
const gl = document.createElement("canvas").getContext("webgl");
const vaoApi = createVAOApi(gl);
const vao = vaoApi?.create();
console.log(vao ? "VAO bereit" : "Keine VAO-Unterstützung");
// Wichtig · Fallstricke
- Nur WebGL 1: In einem WebGL-2-Kontext gibt
getExtension("OES_vertex_array_object")nullzurück. Nimm dortgl.createVertexArray(). - Immer mit dem Kontext prüfen: Die Erweiterung wird praktisch überall unterstützt, auch auf Mobilgeräten. Trotzdem solltest du vor der Nutzung auf
nullprüfen. ARRAY_BUFFERwird nicht gespeichert: Das VAO merkt sich nicht die aktuelleARRAY_BUFFER-Bindung selbst. Es speichert nur den Buffer, der beim Aufruf vonvertexAttribPointer()gebunden war. DenELEMENT_ARRAY_BUFFERspeichert es dagegen schon. Wenn du ihn bindest, während ein VAO aktiv ist, veränderst du also dieses VAO.- Nach der Einrichtung entbinden: Rufe danach
bindVertexArrayOES(null)auf. So veränderst du nicht aus Versehen den Zustand des VAOs, zum Beispiel in Code von Drittbibliotheken, der nichts von VAOs weiß. - Speicher freigeben: Nicht mehr benötigte VAOs löschst du mit
deleteVertexArrayOES(). Wenn der Kontext verloren geht (webglcontextlost), werden alle VAOs ungültig und müssen neu erzeugt werden. - VAOs sind an den Kontext gebunden, in dem sie erzeugt wurden. Zwischen verschiedenen Kontexten kannst du sie nicht teilen.