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

WebGLRenderingContext.getAttribLocation()

Methode

Gibt den Index (die Position) einer <code>attribute</code>- bzw. <code>in</code>-Variablen des Vertex-Shaders in einem gelinkten <code>WebGLProgram</code> zurück.

seit JavaScript Baseline: alle Browser (WebGL 1.0) Kategorie: webapi

Signatur

WebGLRenderingContext.prototype.getAttribLocation(program, name)

Beschreibung

getAttribLocation() ermittelt, unter welchem numerischen Index eine Attributvariable des Vertex-Shaders (in GLSL ES 1.0 attribute, in GLSL ES 3.0 in) im gelinkten Programm liegt. Diesen Index brauchst du, um Vertex-Daten aus einem Buffer mit dem Attribut zu verbinden, also für vertexAttribPointer(), enableVertexAttribArray() und vertexAttrib[1234]f[v]().

Normalerweise fragst du die Positionen einmal direkt nach linkProgram() ab und speicherst sie. Du solltest sie nicht in jedem Frame neu abfragen, denn der Aufruf kostet Zeit und die Werte ändern sich nur, wenn das Programm neu gelinkt wird.

Hat der Shader die Variable nicht deklariert oder der Compiler sie wegoptimiert, weil sie nicht verwendet wird, gibt die Methode -1 zurück. Wenn du selbst festlegen willst, welches Attribut welchen Index bekommt, rufst du vor dem Linken bindAttribLocation() auf. In WebGL 2 kannst du den Index auch im Shader mit layout(location = n) festlegen.

Parameter

Name Typ Default Beschreibung
$program Pflicht WebGLProgram Das Programm mit dem Attribut. Es muss bereits erfolgreich mit linkProgram() gelinkt sein.
$name Pflicht string Name der Attributvariablen genau so, wie er im Shader-Quelltext steht (Groß-/Kleinschreibung zählt), z. B. "a_position". Namen mit dem Präfix webgl_ oder _webgl_ sind reserviert.

Rückgabewert

Typ
GLint (number)
Beschreibung
Index des Attributs, eine Zahl ≥ 0. Ist das Attribut nicht vorhanden, nicht aktiv oder der Name reserviert, ist der Wert -1.

Beispiele

Attributposition abfragen und Buffer verbinden

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

const vsSource = `
  attribute vec2 a_position;
  void main() {
    gl_Position = vec4(a_position, 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 shader = gl.createShader(type);
  gl.shaderSource(shader, src);
  gl.compileShader(shader);
  return shader;
};

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

// Position einmal nach dem Linken abfragen
const positionLoc = gl.getAttribLocation(program, 'a_position');
console.log('a_position liegt an Index', positionLoc);

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);

gl.useProgram(program);
gl.enableVertexAttribArray(positionLoc);
gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 3);
a_position liegt an Index 0

Fehlende oder wegoptimierte Attribute erkennen

// program: ein bereits gelinktes WebGLProgram
const getAttribs = (gl, program, names) => {
  const locations = {};
  for (const name of names) {
    const loc = gl.getAttribLocation(program, name);
    if (loc === -1) {
      console.warn(`Attribut "${name}" nicht gefunden oder unbenutzt`);
      continue;
    }
    locations[name] = loc;
  }
  return locations;
};

const attribs = getAttribs(gl, program, ['a_position', 'a_color']);
console.log(attribs);
Attribut "a_color" nicht gefunden oder unbenutzt { a_position: 0 }

Alle aktiven Attribute auflisten

const count = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
for (let i = 0; i < count; i++) {
  const info = gl.getActiveAttrib(program, i);
  const loc = gl.getAttribLocation(program, info.name);
  console.log(`${info.name} -> Index ${loc}`);
}
a_position -> Index 0

// Wichtig · Fallstricke

  • Nur nach dem Linken gültig: Vor linkProgram() oder bei einem fehlgeschlagenen Linkvorgang führt der Aufruf zu gl.INVALID_OPERATION. Prüfe deshalb vorher gl.getProgramParameter(program, gl.LINK_STATUS).
  • Rückgabewert -1 immer prüfen: Übergibst du -1 an enableVertexAttribArray() oder vertexAttribPointer(), erzeugt das gl.INVALID_VALUE. Der häufigste Grund für -1 ist ein Attribut, das im Shader zwar deklariert, aber nicht benutzt wird. Der Compiler entfernt es dann.
  • Die Rückgabe ist eine Zahl, kein Objekt: Bei getUniformLocation() bekommst du ein WebGLUniformLocation-Objekt oder null. Verwechsle die beiden Prüfungen nicht.
  • Indizes sind nicht festgelegt: Verlass dich nicht darauf, dass die Reihenfolge im Shader den Indizes entspricht. Wenn mehrere Programme dieselbe Anordnung brauchen, zum Beispiel beim Teilen von Vertex Array Objects, verwende bindAttribLocation() oder in WebGL 2 layout(location = n).
  • Performance: Speichere die Positionen zwischen, statt sie in der Render-Schleife abzufragen.
  • Kompatibilität: Die Methode gibt es in allen modernen Browsern, sowohl in WebGLRenderingContext als auch in WebGL2RenderingContext. Nach einem Kontextverlust (webglcontextlost) gibt sie -1 zurück.