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

WebGL2RenderingContext.bindVertexArray()

Methode

Bindet ein <code>WebGLVertexArrayObject</code> (VAO) als aktuelles Vertex-Array, sodass dessen gespeicherte Attribut-Konfiguration für Zeichenaufrufe gilt.

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

Signatur

WebGL2RenderingContext.prototype.bindVertexArray(vertexArray)

Beschreibung

bindVertexArray() macht ein Vertex Array Object (VAO) zum aktiven Vertex-Array des WebGL-2-Kontexts. Ein VAO speichert den kompletten Zustand der Vertex-Attribute: welche Attribute mit enableVertexAttribArray() aktiviert sind, deren Layout aus vertexAttribPointer() bzw. vertexAttribIPointer(), die Divisoren aus vertexAttribDivisor() und den gebundenen ELEMENT_ARRAY_BUFFER.

So läuft das typischerweise ab: Beim Initialisieren legst du für jedes Mesh ein VAO an, bindest es und konfigurierst die Attribute einmal. Beim Rendern reicht dann pro Objekt ein einziger bindVertexArray(vao)-Aufruf vor drawArrays() oder drawElements(). Das spart viele API-Aufrufe und senkt den CPU-Aufwand spürbar.

Mit null bindest du wieder das Standard-Vertex-Array. Das solltest du nach dem Einrichten eines VAOs tun, damit spätere Aufrufe von bindBuffer(gl.ELEMENT_ARRAY_BUFFER, …) oder Attribut-Änderungen das VAO nicht aus Versehen verändern.

Wichtig: Der gebundene ARRAY_BUFFER gehört nicht zum VAO-Zustand. Maßgeblich ist nur der Puffer, der beim Aufruf von vertexAttribPointer() gebunden war. Diese Referenz wird pro Attribut im VAO gespeichert.

Parameter

Name Typ Default Beschreibung
$vertexArray Pflicht WebGLVertexArrayObject | null Das zu bindende VAO, erzeugt mit gl.createVertexArray(). Mit null wird wieder das Standard-Vertex-Array gebunden.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Fehler erkennst du über gl.getError().

Beispiele

VAO für ein Dreieck einrichten und zeichnen

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2');

const vsSource = `#version 300 es
in vec2 aPosition;
void main() { gl_Position = vec4(aPosition, 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);
  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 – ab jetzt wird der 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, 'aPosition');
gl.enableVertexAttribArray(loc);
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);

// Standard-Vertex-Array wieder binden, damit das VAO nicht versehentlich verändert wird
gl.bindVertexArray(null);

// Rendern: ein einziger Bind-Aufruf genügt
gl.useProgram(program);
gl.bindVertexArray(vao);
gl.drawArrays(gl.TRIANGLES, 0, 3);
gl.bindVertexArray(null);

Mehrere Meshes mit je eigenem VAO rendern (inkl. Index-Puffer)

// gl und program wie oben erstellt
const createMesh = (positions, 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(positions), gl.STATIC_DRAW);
  gl.enableVertexAttribArray(0);
  gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);

  // Der ELEMENT_ARRAY_BUFFER wird 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, count: indices.length };
};

gl.bindAttribLocation(program, 0, 'aPosition');
gl.linkProgram(program);

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.5, 0.9, -0.5, 0.5, 0.5], [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);

Aktuell gebundenes VAO abfragen und aufräumen

const vao = gl.createVertexArray();
gl.bindVertexArray(vao);

console.log(gl.getParameter(gl.VERTEX_ARRAY_BINDING) === vao);
console.log(gl.isVertexArray(vao));

gl.bindVertexArray(null);
gl.deleteVertexArray(vao);
console.log(gl.isVertexArray(vao));
true true false

// Wichtig · Fallstricke

  • Nur in WebGL 2: In WebGL 1 gibt es VAOs nur über die Erweiterung OES_vertex_array_object. Dort heißt der Aufruf ext.bindVertexArrayOES(vao). WebGL 2 wird von allen aktuellen Browsern unterstützt (Safari seit Version 15).
  • ARRAY_BUFFER gehört nicht zum VAO: Nur ELEMENT_ARRAY_BUFFER und die Attribut-Zeiger werden gespeichert. Wenn du bindBuffer(gl.ELEMENT_ARRAY_BUFFER, …) aufrufst, während ein VAO gebunden ist, überschreibst du dessen Index-Puffer. Deshalb nach dem Einrichten bindVertexArray(null) aufrufen.
  • Wenn du ein gelöschtes VAO bindest oder eines aus einem anderen Kontext, entsteht INVALID_OPERATION.
  • Löschst du mit deleteVertexArray() das gerade gebundene VAO, wird automatisch das Standard-Vertex-Array gebunden.
  • Die Attribut-Positionen müssen zu jedem Programm passen, mit dem du das VAO nutzt. Mit bindAttribLocation() oder layout(location = N) im Shader legst du feste Positionen fest.
  • Geht der Kontext verloren (webglcontextlost), werden alle VAOs ungültig und müssen neu erzeugt werden.