Start · Sprachen · JavaScript · Referenz · WebGL2RenderingContext.createVertexArray()

WebGL2RenderingContext.createVertexArray()

Methode

Erstellt ein neues <code>WebGLVertexArrayObject</code> (VAO), das die Konfiguration der Vertex-Attribute und den Index-Buffer bündelt.

seit JavaScript WebGL 2 – Baseline: alle modernen Browser (seit 20 Kategorie: webapi

Signatur

WebGL2RenderingContext.prototype.createVertexArray()

Beschreibung

Die Methode createVertexArray() erzeugt ein leeres Vertex Array Object (VAO). Ein VAO speichert den gesamten Zustand, der beschreibt, wie Vertex-Daten aus Buffern gelesen werden: alle Aufrufe von vertexAttribPointer(), vertexAttribIPointer(), enableVertexAttribArray(), vertexAttribDivisor() sowie den gebundenen ELEMENT_ARRAY_BUFFER.

Der typische Ablauf: VAO erstellen, mit bindVertexArray(vao) binden, Buffer und Attribute einmalig konfigurieren und anschließend das VAO lösen (bindVertexArray(null)). Beim Zeichnen reicht dann ein einziger bindVertexArray()-Aufruf, um die komplette Konfiguration wiederherzustellen. Das spart viele API-Aufrufe pro Frame und macht den Code übersichtlicher, besonders bei vielen Objekten mit unterschiedlichen Vertex-Layouts.

In WebGL 1 war diese Funktionalität nur über die Erweiterung OES_vertex_array_object (createVertexArrayOES()) verfügbar. In WebGL 2 ist sie fester Bestandteil der API.

Rückgabewert

Typ
WebGLVertexArrayObject | null
Beschreibung
Ein neues, noch ungebundenes WebGLVertexArrayObject. Ist der Kontext verloren (context lost), wird null zurückgegeben.

Beispiele

VAO für ein Dreieck einrichten und zeichnen

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2');
if (!gl) throw new Error('WebGL 2 wird nicht unterstützt');

const vsSource = `#version 300 es
in vec2 a_position;
void main() { gl_Position = vec4(a_position, 0.0, 1.0); }`;
const fsSource = `#version 300 es
precision mediump float;
out vec4 outColor;
void main() { outColor = 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);
  if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(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 erstellen und binden – ab jetzt wird Attribut-Zustand darin gespeichert
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);

const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0.5, -0.5, -0.5, 0.5, -0.5]), gl.STATIC_DRAW);

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

gl.bindVertexArray(null); // Konfiguration abgeschlossen

// Zeichnen: ein Bind genügt
gl.useProgram(program);
gl.bindVertexArray(vao);
gl.drawArrays(gl.TRIANGLES, 0, 3);
console.log(gl.isVertexArray(vao));
true

Mehrere Meshes mit eigenem VAO und Index-Buffer

// Annahme: gl (WebGL2) und program existieren, Attribut 'a_position' an Location 0
gl.bindAttribLocation(program, 0, 'a_position');
gl.linkProgram(program);

const createMesh = (vertices, indices) => {
  const vao = gl.createVertexArray();
  gl.bindVertexArray(vao);

  const vbo = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
  gl.enableVertexAttribArray(0);
  gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);

  // Der Index-Buffer wird ebenfalls im VAO gespeichert
  const ibo = gl.createBuffer();
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);

  gl.bindVertexArray(null);
  return { vao, vbo, ibo, count: indices.length };
};

const quad = createMesh([-0.9, -0.9, -0.1, -0.9, -0.1, -0.1, -0.9, -0.1], [0, 1, 2, 0, 2, 3]);
const tri = createMesh([0.1, 0.1, 0.9, 0.1, 0.5, 0.9], [0, 1, 2]);

const render = () => {
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.useProgram(program);
  for (const mesh of [quad, tri]) {
    gl.bindVertexArray(mesh.vao);
    gl.drawElements(gl.TRIANGLES, mesh.count, gl.UNSIGNED_SHORT, 0);
  }
  gl.bindVertexArray(null);
  requestAnimationFrame(render);
};
requestAnimationFrame(render);

Aufräumen und Fallback auf WebGL 1

const canvas = document.createElement('canvas');
const gl2 = canvas.getContext('webgl2');

let createVAO, bindVAO, deleteVAO;
if (gl2) {
  createVAO = () => gl2.createVertexArray();
  bindVAO = (vao) => gl2.bindVertexArray(vao);
  deleteVAO = (vao) => gl2.deleteVertexArray(vao);
} else {
  const gl1 = canvas.getContext('webgl');
  const ext = gl1?.getExtension('OES_vertex_array_object');
  if (!ext) throw new Error('Keine VAO-Unterstützung');
  createVAO = () => ext.createVertexArrayOES();
  bindVAO = (vao) => ext.bindVertexArrayOES(vao);
  deleteVAO = (vao) => ext.deleteVertexArrayOES(vao);
}

const vao = createVAO();
bindVAO(vao);
// ... Attribute konfigurieren ...
bindVAO(null);

// Nicht mehr benötigte VAOs explizit freigeben
deleteVAO(vao);
console.log(gl2 ? gl2.isVertexArray(vao) : 'WebGL 1');
false

// Wichtig · Fallstricke

  • Erst binden, dann konfigurieren: Ein frisch erstelltes VAO ist leer. Attribut-Aufrufe wirken nur auf das aktuell gebundene VAO – wer bindVertexArray(vao) vergisst, verändert das Standard-VAO (null).
  • ARRAY_BUFFER ist nicht Teil des VAO-Zustands: Gespeichert wird nur, welcher Buffer beim Aufruf von vertexAttribPointer() gebunden war. Der ELEMENT_ARRAY_BUFFER dagegen wird direkt im VAO gespeichert – ihn also nicht lösen, solange das VAO noch gebunden ist.
  • Nach der Einrichtung lösen: bindVertexArray(null) verhindert, dass späterer Code versehentlich ein VAO verändert.
  • Speicher: VAOs werden nicht zuverlässig vom Garbage Collector freigegeben; mit deleteVertexArray() explizit löschen.
  • Kontextverlust: Nach webglcontextlost liefert die Methode null; alle VAOs müssen nach webglcontextrestored neu erstellt werden.
  • Kompatibilität: Nur mit einem webgl2-Kontext verfügbar (alle aktuellen Browser, Safari ab 15). Für WebGL 1 die Erweiterung OES_vertex_array_object nutzen.