Start · Sprachen · JavaScript · Referenz · WebGLRenderingContext.bindAttribLocation()

WebGLRenderingContext.bindAttribLocation()

Methode

Legt vor dem Linken eines Shader-Programms fest, an welchem generischen Vertex-Attribut-Index eine benannte <code>attribute</code>-Variable liegt.

seit JavaScript WebGL 1.0 – Baseline: alle Browser Kategorie: webapi

Signatur

WebGLRenderingContext.prototype.bindAttribLocation(program, index, name)

Beschreibung

Mit bindAttribLocation() legst du selbst fest, an welchem generischen Vertex-Attribut-Index (0 bis MAX_VERTEX_ATTRIBS - 1) eine Attributvariable des Vertex-Shaders liegt. Ohne diesen Aufruf vergibt der Treiber die Indizes beim Linken selbst, und du musst sie danach mit getAttribLocation() abfragen.

Die Zuordnung wird erst beim nächsten Aufruf von linkProgram() wirksam. Deshalb rufst du die Methode nach attachShader() und vor linkProgram() auf. Rufst du sie nach dem Linken auf, ändert sich nichts, bis du das Programm neu linkst.

Sinnvoll ist das vor allem, wenn mehrere Shader-Programme dasselbe Vertex-Layout nutzen sollen (z. B. a_position immer auf 0, a_normal immer auf 1). Dann kannst du Vertex Array Objects oder Pufferbelegungen für alle Programme wiederverwenden, ohne die Indizes jedes Mal neu abzufragen. Außerdem empfiehlt es sich, Index 0 an ein Attribut zu binden, das tatsächlich als Array genutzt wird (siehe Hinweise).

Du kannst auch Namen binden, die im Shader nicht vorkommen oder vom Compiler wegoptimiert werden. Solche Zuordnungen werden einfach ignoriert. Es ist sogar erlaubt, zwei Namen an denselben Index zu binden (Aliasing). Werden beide Attribute tatsächlich genutzt, schlägt das Linken in WebGL allerdings fehl.

Parameter

Name Typ Default Beschreibung
$program Pflicht WebGLProgram Das Shader-Programm, dessen Attribut-Zuordnung festgelegt werden soll.
$index Pflicht GLuint (number) Generischer Vertex-Attribut-Index. Muss kleiner als gl.getParameter(gl.MAX_VERTEX_ATTRIBS) sein (mindestens 8, meist 16).
$name Pflicht string Name der attribute- bzw. in-Variable im Vertex-Shader, z. B. "a_position". Namen mit dem Präfix webgl_ oder _webgl_ sind reserviert.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Fehler meldet die Methode über gl.getError().

Beispiele

Attribute vor dem Linken festen Indizes zuordnen

const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');

const vsSource = `
  attribute vec3 a_position;
  attribute vec2 a_uv;
  varying vec2 v_uv;
  void main() {
    v_uv = a_uv;
    gl_Position = vec4(a_position, 1.0);
  }`;
const fsSource = `
  precision mediump float;
  varying vec2 v_uv;
  void main() { gl_FragColor = vec4(v_uv, 0.0, 1.0); }`;

const compile = (type, src) => {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, src);
  gl.compileShader(shader);
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    throw new Error(gl.getShaderInfoLog(shader));
  }
  return shader;
};

const program = gl.createProgram();
gl.attachShader(program, compile(gl.VERTEX_SHADER, vsSource));
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, fsSource));

// WICHTIG: vor linkProgram()
gl.bindAttribLocation(program, 0, 'a_position');
gl.bindAttribLocation(program, 1, 'a_uv');

gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
  throw new Error(gl.getProgramInfoLog(program));
}

console.log(gl.getAttribLocation(program, 'a_position'));
console.log(gl.getAttribLocation(program, 'a_uv'));
0 1

Einheitliches Vertex-Layout für mehrere Programme

// Zentrales Layout, das alle Shader-Programme teilen
const ATTRIBS = { a_position: 0, a_normal: 1, a_uv: 2 };

const createProgram = (gl, vs, fs) => {
  const program = gl.createProgram();
  gl.attachShader(program, vs);
  gl.attachShader(program, fs);
  for (const [name, index] of Object.entries(ATTRIBS)) {
    // Nicht vorhandene Attribute werden einfach ignoriert
    gl.bindAttribLocation(program, index, name);
  }
  gl.linkProgram(program);
  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    throw new Error(gl.getProgramInfoLog(program));
  }
  return program;
};

// Pufferbelegung einmalig – gilt für jedes Programm aus createProgram()
const setupPositionBuffer = (gl, buffer) => {
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.enableVertexAttribArray(ATTRIBS.a_position);
  gl.vertexAttribPointer(ATTRIBS.a_position, 3, gl.FLOAT, false, 0, 0);
};

Nachträgliches Binden wirkt erst nach erneutem Linken

// program ist bereits gelinkt, a_position liegt z. B. auf Index 1
gl.bindAttribLocation(program, 3, 'a_position');
console.log(gl.getAttribLocation(program, 'a_position')); // unverändert

gl.linkProgram(program); // jetzt greift die neue Zuordnung
console.log(gl.getAttribLocation(program, 'a_position'));
1 3

// Wichtig · Fallstricke

  • Zeitpunkt: Die Zuordnung greift erst beim nächsten linkProgram(). Ein häufiger Fehler ist der Aufruf nach dem Linken.
  • Index 0: Auf manchen Desktop-Plattformen (vor allem über ANGLE bzw. ältere OpenGL-Treiber) ist es langsamer, wenn Attribut 0 nicht als Array aktiviert ist. Binde deshalb ein immer genutztes Attribut wie a_position an Index 0.
  • Fehler: INVALID_VALUE, wenn index >= MAX_VERTEX_ATTRIBS ist. INVALID_OPERATION, wenn name mit gl_, webgl_ oder _webgl_ beginnt. Enthält der Name ungültige Zeichen oder ist er länger als 256 Zeichen, gibt es ebenfalls einen Fehler.
  • Nur Attribute: Die Methode gilt nur für Attribute. Für Uniforms verwendest du getUniformLocation().
  • WebGL 2: Dort kannst du alternativ im GLSL-ES-3.00-Shader layout(location = 0) in vec3 a_position; schreiben. Eine Layout-Angabe im Shader hat Vorrang vor bindAttribLocation().
  • Kompatibilität: Wird in allen modernen Browsern unterstützt, sowohl in WebGLRenderingContext als auch in WebGL2RenderingContext.